I've normally been creating Prism Events used by the EventAggregator like:
public class SomeEvent : CompositePresentationEvent<SomeEventArgs> { }
public class SomeEventArgs
{
public string Name { get; set; }
}
But while looking at a co-workers code I noticed they did:
public class SomeEvent : CompositePresentationEvent<SomeEvent>
{
public string Name { get; set; }
}
I guess my first question is why does this even compile? It seems to me that it's implementing a class that isn't defined yet. And second, does it negatively affect the application at all, is it negligible, or better?
I guess my first question is why does this even compile?
Which rule in the spec do you believe it's violating?
It seems to me that it's implementing a class that isn't defined yet.
I think you'd have to specify the exact meaning of each of those terms for the statement to be judged as accurate or not. The compiler knows about CompositePresentationEvent
as it's declared elsewhere (presumably) and it knows about SomeEvent
because that's the class being declared. It's like having a field of type Foo
within a class Foo
- entirely valid.
It's also very useful to be able to do this - particularly for comparisons. For example:
public sealed class Foo : IComparable<Foo>
says that any instance of class Foo
knows how to compare itself with another instance, so it can be used for sorting in a type-safe way. In the case of structs, this also allows you to reduce boxing, as calling x.CompareTo(y)
won't need any boxing when x
is known to be of a type which implements IComparable<>
appropriately.
Note that types can get far more interestingly and confusingly recursive. Take this (slightly modified) example from 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>
Here, the aim is to basically end up with two types - a "message" and a "builder" so that you can always construct each from the other. For example:
public class Foo : IMessage<Foo, FooBuilder>
{
...
}
public class FooBuilder : IBuilder<Foo, FooBuilder>
{
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With