Domanda

Con i generici, c'è mai un motivo per creare classi EventArg derivate specifiche

Sembra che ora puoi semplicemente usarli al volo con un'implementazione generica.

Dovrei esaminare tutti i miei esempi e rimuovere le mie classi eventArg (StringEventArgs, MyFooEventArgs, ecc..)

public class EventArgs<T> : EventArgs
{
    public EventArgs(T value)
    {
        m_value = value;
    }

    private T m_value;

    public T Value
    {
        get { return m_value; }
    }
}
È stato utile?

Soluzione

Ciò che stai descrivendo è essenzialmente tuple, valori raggruppati utilizzati per uno scopo particolare.Sono un costrutto utile in programmazione funzionale e supportano molto bene quello stile.

Lo svantaggio è che i loro valori non hanno un nome e richiedono il contesto per essere compresi. EventArgs per loro stessa natura vengono spesso consumati lontano dal contesto di riferimento.Pertanto, in stile tupla EventArgs può creare molta confusione per il consumatore.

Diciamo che abbiamo un evento che indica che una divisione è stata completata e porta il numeratore, il denominatore e il risultato:

public event EventHandler<EventArgs<double, double, double>> Divided;

Il gestore eventi presenta alcune ambiguità:

private void OnDivided(object sender, EventArgs<double, double, double> e)
{
    // I have to just "know" this - it is a convention

    var numerator = e.Value1;
    var denominator = e.Value2;
    var result = e.Value3;
}

Ciò sarebbe molto più chiaro con un EventArgs rappresentare l'evento:

private void OnDivided(object sender, DividedEventArgs e)
{
    var numerator = e.Numerator;
    var denominator = e.Denominator;
    var result = e.Result;
}

Riutilizzabile generico EventArgs le classi facilitano lo sviluppo del meccanismo a scapito dell'espressione dell'intento.

Altri suggerimenti

Guarda l'articolo EventArgs generici personalizzati Matthew Cochran , in quell'articolo descrive come espanderlo ulteriormente con due e tre membri.

L'uso di EventArgs generici ha i loro usi e, naturalmente, i loro abusi, poiché le informazioni sui tipi vengono perse nel processo.

public class City {...}

public delegate void FireNuclearMissile(object sender, EventArgs<City> args);
public event FireNuclearMissile FireNuclearMissileEvent;

public delegate void QueryPopulation(object sender, EventArgs<City> args);
public event QueryPopulation QueryPopulationEvent;

Nel seguente esempio è sicuro per i tipi, ma un po 'più LOC:

class City {...}

public class FireNuclearMissileEventArgs : EventArgs
{
    public FireNuclearMissileEventArgs(City city)
    {
        this.city = city;
    }

    private City city;

    public City City
    {
        get { return this.city; }
    }
}

public delegate void FireNuclearMissile(object sender, FireNuclearMissileEventArgs args);
public event FireNuclearMissile FireNuclearMissileEvent;

public class QueryPopulationEventArgs : EventArgs
{
    public QueryPopulationEventArgs(City city)
    {
        this.city = city;
    }

    private City city;

    public City City
    {
        get { return this.city; }
    }
}

public delegate void QueryPopulation(object sender, QueryPopulationEventArgs args);
public event QueryPopulation QueryPopulationEvent;

Come già affermato da TcK: utilizzare EventArgs<T> se è necessario solo passare un valore, altrimenti derivare da EventArgs (o <=>, qualunque cosa si desideri).

Penso che EventArgs in stile Tuple siano utili. Proprio come Tuple, possono essere usati in modo improprio, ma sembra che la mia pigrizia sia più forte del mio senso di cautela. Ho implementato quanto segue:

public static class TupleEventArgs
{
    static public TupleEventArgs<T1> Create<T1>(T1 item1)
    {
        return new TupleEventArgs<T1>(item1);
    }

    static public TupleEventArgs<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
    {
        return new TupleEventArgs<T1, T2>(item1, item2);
    }

    static public TupleEventArgs<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
    {
        return new TupleEventArgs<T1, T2, T3>(item1, item2, item3);
    }
}

public class TupleEventArgs<T1> : EventArgs
{
    public T1 Item1;

    public TupleEventArgs(T1 item1)
    {
        Item1 = item1;
    }
}

public class TupleEventArgs<T1, T2> : EventArgs
{
    public T1 Item1;
    public T2 Item2;

    public TupleEventArgs(T1 item1, T2 item2)
    {
        Item1 = item1;
        Item2 = item2;
    }
}

public class TupleEventArgs<T1, T2, T3> : EventArgs
{
    public T1 Item1;
    public T2 Item2;
    public T3 Item3;

    public TupleEventArgs(T1 item1, T2 item2, T3 item3)
    {
        Item1 = item1;
        Item2 = item2;
        Item3 = item3;
    }
}

Può essere utilizzato come segue (se utilizzato con estensione del raiser di eventi )

public event EventHandler<TupleEventArgs<string,string,string>> NewEvent;

NewEvent.Raise(this, TupleEventArgs.Create("1", "2", "3"));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top