I have a delegate with a generic type as one of the parameters:
public delegate void UpdatedPropertyDelegate<T>(
RemoteClient callingClient,
ReplicableProperty<T> updatedProp,
ReplicableObject relevantObject
);
Now, I want a public event that can be subscribed to for other classes to use. Therefore, I did:
public event UpdatedPropertyDelegate<T> UpdatedProperty;
However, the compiler doesn't like that. I don't understand why T has to be specified here. Surely it's specified when I fire the event, i.e.:
if (UpdatedProperty != null)
{
UpdatedProperty(this, readProperty,
ReplicableObjectBin.GetObjectByID(readProperty.OwnerID));
}
So, am I doing something simple wrong? Or is this a massive failure of understanding?
Thanks.
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.
C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.
What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.
It sounds like what you need is an interface type, rather than a delegate. Interface methods can accept open generic types (which is what you're after), even though delegates cannot. For example, one could define something like:
interface ActOnConstrainedThing<CT1,CT2>
{
void Act<MainType>(MainType param) where MainType: CT1,CT2;
}
Even if implementers of CT1
and CT2
do not share a common base type which also implements CT1
and CT2
, an implementation of Act
may use its passed-in parameter as a CT1
or CT2
without typecast, and could even pass it to routines which expect a generic parameter with CT1
and CT2
constraints. Such a thing would not be possible with delegates.
Note that using interfaces rather than delegates means that one cannot use the normal "event" mechanism and syntax. Instead, the object which would be an event publisher must maintain a list of object instances that implement the desired interface (e.g. a List<ActOnConstrainedThing<IThis,IThat>>
) , and enumerate the instances on that list (perhaps using foreeach
). For example:
List<IActOnConstrainedThing<IThis,IThat>> _ActOnThingSubscribers; void ActOnThings<T>(T param) where T:IThis,IThat { foreach(var thing in _ActOnThingSubscribers) { thing.Act<T>(param); } }
Edit/Addendum
The place where I employed this pattern also had some other stuff that didn't seem overly relevant to the question, which by my interpretation was asking how one can have a delegate (or equivalent) with an open type parameter, so that the object invoking the delegate-equivalent can supply the type parameter, without the object supplying the delegate having to know it in advance. Most cases where this is useful involve generic constraints, but since that was apparently introducing confusion, here's an example that doesn't:
interface IShuffleFiveThings { void Shuffle<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5); } List<IShuffleFiveThings _ShuffleSubscribers; void ApplyShuffles<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5) { foreach(var shuffler in _ShuffleSubscribers) { thing.Shuffle(ref p1, ref p2, ref p3, ref p4, ref p5); } }
The IShuffleFiveThings.Shuffle<T>
method takes five parameters by ref
and does something with them (most likely permutes them in some fashion; perhaps permuting them randomly, or perhaps permuting some randomly while leaving others where they are. If one has a list IShuffleFiveThings
, the things in that list can be used efficiently, without boxing or Reflection, to manipulate any kind of thing (including both class types and value types). By contrast, if one were to use delegates:
delegate void ActOn5RefParameters(ref p1, ref p2, ref p3, ref p4, ref p5);
then because any particular delegate instance can only act upon a single parameter type supplied at its creation (unless it's an open delegate which is called only via Reflection), one would need to create a separate list of delegates for every type of object one wished to shuffle (yes, I know one would normally handle permutations by using an array of integer indices; I chose permutation as an operation because it's applicable to all object types, not because this particular method of permuting things is useful).
Note that because the type T
in IShuffleFiveThings
does not have any constraints, implementations won't be able to do much with it except by typecasting (which may introduce boxing). Adding constraints to such parameters makes them much more useful. While it would be possible to hard-code such constraints within the interface, that would limit the interface's usefulness to applications requiring those particular constraints. Making the constraints themselves generic avoids that restriction.
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