2012-05-22 10 views
6

Ho normalmente creando Prism eventi utilizzati dal EventAggregator come:Definire la classe con se stessa come implementazione generica. Perché/come funziona?

public class SomeEvent : CompositePresentationEvent<SomeEventArgs> { }

public class SomeEventArgs 
{ 
    public string Name { get; set; } 
} 

Ma mentre guardando un codice di collaboratori ho notato che hanno fatto:

public class SomeEvent : CompositePresentationEvent<SomeEvent> 
{ 
    public string Name { get; set; } 
} 

I Immagino che la mia prima domanda sia: perché questo si compila anche? Mi sembra che stia implementando una classe che non è ancora stata definita. E in secondo luogo, influisce negativamente sull'applicazione, è trascurabile o migliore?

+0

Nota: in realtà non sta * implementando * la classe, semplicemente facendo uso di essa. SecondNote: sono d'accordo che questo è strano (+1). L'implementazione rispetto all'uso in una classe base è diversa, ma strana. – Crisfole

+3

Benvenuto in [* Modello di modello che ricorre in modo curioso *] (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) – dasblinkenlight

risposta

8

Suppongo che la mia prima domanda sia: perché questo viene compilato?

Quale regola delle specifiche ritieni che stia violando?

Mi sembra che stia implementando una classe che non è ancora stata definita.

penso che avrei dovuto specificare l'esatto significato di ciascuno di questi termini per la dichiarazione di essere giudicato più accurate o no. Il compilatore sa di CompositePresentationEvent come viene dichiarato altrove (presumibilmente) e conosce SomeEvent perché è la classe dichiarata. È come avere un campo di tipo Foo all'interno di una classe - interamente valido.

E 'anche molto utile per essere in grado di fare questo - in particolare per i confronti. Per esempio:

public sealed class Foo : IComparable<Foo> 

dice che qualsiasi istanza della classe Foo sa come confrontarsi con un altro esempio, in modo che possa essere utilizzato per l'ordinamento in modo type-safe. Nel caso delle strutture, questo consente anche di ridurre la boxe, poiché chiamare x.CompareTo(y) non avrà bisogno di alcun boxing quando lo x è noto per essere di un tipo che implementa IComparable<> in modo appropriato.

Nota che i tipi possono ottenere lontano in modo più interessante e ricorsivo in modo confuso. Prendete questo esempio (leggermente modificato) da my port of Protocol Buffers:

public interface IMessage<TMessage, TBuilder> 
    where TMessage : IMessage<TMessage, TBuilder> 
    where TBuilder : IBuilder<TMessage, TBuilder> 

public interface IBuilder<TMessage, TBuilder> 
    where TMessage : IMessage<TMessage, TBuilder> 
    where TBuilder : IBuilder<TMessage, TBuilder> 

Qui, l'obiettivo è quello di finire in fondo con due tipi - un "messaggio" e di un "costruttore" in modo che si può sempre costruire uno dall'altro. Ad esempio:

public class Foo : IMessage<Foo, FooBuilder> 
{ 
    ... 
} 

public class FooBuilder : IBuilder<Foo, FooBuilder> 
{ 
    ... 
} 
+4

Ha persino un nome. Vedi http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

Problemi correlati