Domanda

Ogni volta che lo avvio in profondo in un progetto C#, io alla fine con un sacco di eventi che davvero solo bisogno di passare un singolo elemento.Io bastone con la EventHandler/EventArgs la pratica, ma la cosa che mi piace fare è avere qualcosa di simile:

public delegate void EventHandler<T>(object src, EventArgs<T> args);

public class EventArgs<T>: EventArgs {

  private T item;

  public EventArgs(T item) {
    this.item = item;
  }

  public T Item {
    get { return item; }
  }
}

Più tardi, posso avere il mio

public event EventHandler<Foo> FooChanged;

public event EventHandler<Bar> BarChanged;

Tuttavia, sembra che lo standard per .NET è quello di creare un nuovo delegato e EventArgs sottoclasse per ogni tipo di evento.C'è qualcosa di sbagliato con il mio approccio generico?


EDIT:Il motivo di questo post è che ho appena ri-creata in un nuovo progetto, e voleva assicurarsi che fosse ok.In realtà, mi è stato ri-creazione come ho postato.Ho trovato che c'è un generico EventHandler<TEventArgs>, quindi non c'è bisogno di creare il delegato generico, ma è ancora necessario il generico EventArgs<T> di classe, perché TEventArgs: EventArgs.
Un'altra MODIFICA:Un difetto (per me) la soluzione integrata è il dettaglio:

public event EventHandler<EventArgs<Foo>> FooChanged;

vs

public event EventHandler<Foo> FooChanged;

Può essere un dolore per i clienti di registrarsi per i vostri eventi, però, perché lo spazio dei nomi System è importate per impostazione predefinita, in modo che manualmente cercare il vostro spazio dei nomi, anche con una fantasia come strumento di Resharper...Qualcuno ha idee relative a questo?

È stato utile?

Soluzione

Delegato del seguente modulo è stato aggiunto da .NET Framework 2.0

public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs

L'approccio va un po 'oltre, poiché si fornisce un'implementazione immediata per EventArgs con un singolo elemento di dati, ma manca di diverse proprietà dell'idea originale:

  1. Non è possibile aggiungere più proprietà ai dati dell'evento senza modificare il codice dipendente. Dovrai modificare la firma del delegato per fornire più dati al sottoscrittore dell'evento.
  2. Il tuo oggetto dati è generico, ma è anche " anonimo " ;, e durante la lettura del codice dovrai decifrare " Item " proprietà dagli usi. Dovrebbe essere nominato in base ai dati forniti.
  3. Usando i generici in questo modo non è possibile creare una gerarchia parallela di EventArgs, quando si dispone di una gerarchia di tipi (oggetto) sottostanti. Per esempio. EventArgs lt &; BaseType gt &; non è un tipo di base per EventArgs < DerivedType > ;, anche se BaseType è base per DerivedType.

Quindi, penso che sia meglio usare EventHandler generico < T > ;, ma abbia ancora classi EventArgs personalizzate, organizzate secondo i requisiti del modello di dati. Con Visual Studio ed estensioni come ReSharper, sono solo pochi i comandi per creare una nuova classe come quella.

Altri suggerimenti

Per rendere la generica dichiarazione di evento più facile, ho creato un paio di frammenti di codice per farlo.Uso:

  • Copiare l'intero frammento.
  • Incolla in un file di testo (ad es.nel blocco note).
  • Salvare il file con un .frammento di estensione.
  • Mettere l' .frammento di file appropriato frammento di directory, ad esempio:

Visual Studio 2008\Frammenti Di Codice\Visual C#\I Miei Frammenti Di Codice

Ecco uno che usa una custom EventArgs classe con una proprietà:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>Generic event with one type/argument.</Title>
            <Shortcut>ev1Generic</Shortcut>
            <Description>Code snippet for event handler and On method</Description>
            <Author>Kyralessa</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
        <Literal>
          <ID>type</ID>
          <ToolTip>Type of the property in the EventArgs subclass.</ToolTip>
          <Default>propertyType</Default>
        </Literal>
        <Literal>
          <ID>argName</ID>
          <ToolTip>Name of the argument in the EventArgs subclass constructor.</ToolTip>
          <Default>propertyName</Default>
        </Literal>
        <Literal>
          <ID>propertyName</ID>
          <ToolTip>Name of the property in the EventArgs subclass.</ToolTip>
          <Default>PropertyName</Default>
        </Literal>
        <Literal>
          <ID>eventName</ID>
          <ToolTip>Name of the event</ToolTip>
          <Default>NameOfEvent</Default>
        </Literal>
            </Declarations>
      <Code Language="CSharp"><![CDATA[public class $eventName$EventArgs : System.EventArgs
      {
        public $eventName$EventArgs($type$ $argName$)
        {
          this.$propertyName$ = $argName$;
        }

        public $type$ $propertyName$ { get; private set; }
      }

      public event EventHandler<$eventName$EventArgs> $eventName$;
            protected virtual void On$eventName$($eventName$EventArgs e)
            {
                var handler = $eventName$;
                if (handler != null)
                    handler(this, e);
            }]]>
      </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

E qui è uno che ha due proprietà:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Generic event with two types/arguments.</Title>
      <Shortcut>ev2Generic</Shortcut>
      <Description>Code snippet for event handler and On method</Description>
      <Author>Kyralessa</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>type1</ID>
          <ToolTip>Type of the first property in the EventArgs subclass.</ToolTip>
          <Default>propertyType1</Default>
        </Literal>
        <Literal>
          <ID>arg1Name</ID>
          <ToolTip>Name of the first argument in the EventArgs subclass constructor.</ToolTip>
          <Default>property1Name</Default>
        </Literal>
        <Literal>
          <ID>property1Name</ID>
          <ToolTip>Name of the first property in the EventArgs subclass.</ToolTip>
          <Default>Property1Name</Default>
        </Literal>
        <Literal>
          <ID>type2</ID>
          <ToolTip>Type of the second property in the EventArgs subclass.</ToolTip>
          <Default>propertyType1</Default>
        </Literal>
        <Literal>
          <ID>arg2Name</ID>
          <ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip>
          <Default>property1Name</Default>
        </Literal>
        <Literal>
          <ID>property2Name</ID>
          <ToolTip>Name of the second property in the EventArgs subclass.</ToolTip>
          <Default>Property2Name</Default>
        </Literal>
        <Literal>
          <ID>eventName</ID>
          <ToolTip>Name of the event</ToolTip>
          <Default>NameOfEvent</Default>
        </Literal>
      </Declarations>
      <Code Language="CSharp">
        <![CDATA[public class $eventName$EventArgs : System.EventArgs
      {
        public $eventName$EventArgs($type1$ $arg1Name$, $type2$ $arg2Name$)
        {
          this.$property1Name$ = $arg1Name$;
          this.$property2Name$ = $arg2Name$;
        }

        public $type1$ $property1Name$ { get; private set; }
        public $type2$ $property2Name$ { get; private set; }
      }

      public event EventHandler<$eventName$EventArgs> $eventName$;
            protected virtual void On$eventName$($eventName$EventArgs e)
            {
                var handler = $eventName$;
                if (handler != null)
                    handler(this, e);
            }]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

È possibile seguire il modello per creare loro proprietà come molti come ti piace.

No, non penso che questo sia l'approccio sbagliato. Penso che sia persino raccomandato nel [fantastico] libro Linee guida per la progettazione di framework . Faccio la stessa cosa.

Questa è l'implementazione corretta. È stato aggiunto a .NET Framework (mscorlib) dalla prima generazione di generics (2.0).

Per ulteriori informazioni sull'uso e l'implementazione, consultare MSDN: http: // msdn .microsoft.com / en-us / library / db0etb8x.aspx

La prima volta che ho visto questo piccolo schema, stavo usando Blocco applicazione dell'interfaccia utente composita , da MS Patterns & amp; Gruppo di esercitazioni.

Non mi lancia nessuna bandiera rossa; in effetti è anche un modo intelligente di sfruttare i generici per seguire la regola DRY . / p>

Da .NET 2.0

  

EventHandler<T>

è stato implementato.

Puoi trovare EventHandler generico su MSDN http://msdn.microsoft. com / it-it / library / db0etb8x.aspx

Ho ampiamente utilizzato EventHandler generico ed è stato in grado di prevenire il cosiddetto " Explosion of Types (Classes) " Il progetto è stato mantenuto più piccolo e più facile da navigare.

Presentare un nuovo delegato intuitivo per un delegato EventHandler non generico è doloroso e si sovrappone a tipi esistenti Aggiunta & Quot; * EventHandler & Quot; a mio nome di delegato non aiuta molto secondo me

Credo che le versioni recenti di .NET abbiano appena definito un tale gestore di eventi. Questo è un grande pollice in alto per quanto mi riguarda.

/ EDIT

Non ho ottenuto la distinzione lì originariamente. Finché passi indietro una classe che eredita da EventArgs, cosa che sei, non vedo alcun problema. Sarei preoccupato se non steste avvolgendo il risultato per motivi di manutenibilità. Dico ancora che mi sta bene.

Utilizza istanze generiche del gestore eventi

Prima di .NET Framework 2.0, per passare informazioni personalizzate al gestore eventi, era necessario dichiarare un nuovo delegato che specificasse una classe derivata dalla classe System.EventArgs. Questo non è più vero in .NET

Framework 2.0, che ha introdotto il delegato System.EventHandler < T >). Questo delegato generico consente di utilizzare qualsiasi classe derivata da EventArgs con il gestore eventi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top