I have an event Load
public delegate void OnLoad(int i);
public event OnLoad Load;
I subscribe to it with a method:
public void Go()
{
Load += (x) => { };
}
Is it possible to retrieve this method using reflection? How?
In this particular case you could, with reflection. However, in general, you can't. Events encapsulate the idea of subscribers subscribing and unsubscribing - and that's all. A subscriber isn't meant to find out what other subscribers there are.
A field-like event as you've just shown is simply backed by a field of the relevant delegate type, with autogenerated add/remove handlers which just use the field. However, there's nothing to say they have to be implemented like that. For example, an event can store its subscribers in an EventHandlerList, which is efficient if you have several events in a class and only a few of them are likely to be subscribed to.
Now I suppose you could try to find the body of the "add" handler, decompile it and work out how the event handlers are being stored, and fetch them that way... but please don't. You're creating a lot of work, just to break encapsulation. Just redesign your code so that you don't need to do this.
EDIT: I've been assuming that you're talking about getting the subscribers from outside the class declaring the event. If you're inside the class declaring the event, then it's easy, because you know how the event is being stored.
At that point, the problem goes from "fetching the subscribers of an event" to "fetching the individual delegates making up a multicast delegate" - and that's easy. As others have said, you can call Delegate.GetInvocationList to get an array of delegates... and then use the Delegate.Method property to get the method that that particular delegate targets.
Now, let's look again at your subscription code:
public void Go()
{
Load += (x) => { };
}
The method that's used to create the delegate here isn't Go... it's a method created by the C# compiler. It will have an "unspeakable name" (usually with angle brackets) so will look something like this:
[CompilerGenerated]
private static void <Go>b__0(int x)
{
}
Now, is that actually what you want to retrieve? Or were you really looking to find out which method performed the subscription, rather than which method was used as the subscribed handler?
If you call Load.GetInvocationList() you will be handed back an array of Delegate types. From the these types, you can access the MethodInfo.
You could use the GetInvocationList method which will give you all the subscribers.
Related
I have a question regarding raising base class events. I am currently reading the MSDN C# Programming Guide and I cannot understand one thing from the below article:
http://msdn.microsoft.com/en-us/library/vstudio/hy3sefw3.aspx
public void AddShape(Shape s)
{
_list.Add(s);
s.ShapeChanged += HandleShapeChanged;
}
OK, so we are registering the delegate with an event and we'll be calling the private method HandleShapeChanged when the event is raised.
public void Update(double d)
{
radius = d;
area = Math.PI * radius * radius;
OnShapeChanged(new ShapeEventArgs(area));
}
protected override void OnShapeChanged(ShapeEventArgs e)
{
base.OnShapeChanged(e);
}
And here we are calling the base class method OnShapeChanged, which, in success, will fire the event. But the event is based in the Shape class, so how can it access the method HandleShapeChanged, which is private?
I have just started to learn the language, so please bear with me. My understanding of this example may be well off target.
I see the way you are thinking, it feels like another class is calling a private method. But no, the best way to think about it is that access rules are checked when the delegate is created, not when it is invoked. And that of course is no problem, the class can access its own private method.
Also checking it when it is invoked would be lousy, that would require making the event handler public. And handling events is almost always a very private implementation detail of a class that no external code should ever be allowed to call directly. Since that would mean that you couldn't be sure in your event handler that it was actually the event that triggered the call. That's bad, very bad.
The event is invoking the delegate. It doesn't matter what code is in the delegate. Since the method is not being invoked explicitly, access rules do not apply.
Note also that this has nothing to do with the fact that the event is in a base class. The exact same thing would happen even if the event were in a totally unrelated class.
public class TestA
{
public event Action<int> updateEvent;
...
if(updateEvent != null)
{
Actin<int> tempEvent = updateEvent;
updateEvent(1);
}
}
public class TestB
{
public Action<int> updateEvent;
...
if(updateEvent != null)
{
Actin<int> tempEvent = updateEvent;
updateEvent(1);
}
}
however event Action<T> is eventQueue au
use same and resutl same. What is more good? (i like TestB. Because simple using.)
The event modifier is useful to prevent an assignment. What does it mean? If that's a callback with many handlers attached you may want to prevent that someone simply write:
myObject.UpdateEvent = null or something like that. With event they can't do that. Take a look at Learning C# 3.0: Master the fundamentals of C# 3.0.
The code you use to call the event isn't bad but not so useful, if you assign the delegate to temporary variable you may want to be somehow thread-safe (someone could unhook after your null check) so you should do it before the check:
Action<int> tempEvent = updateEvent;
if (tempEvent != null)
tempEvent(1);
A little side note: if you use events you may want to follow .NET Framework patterns and guidelines, take a look at MSDN
To the compiler, the difference is that the event cannot be invoked except by the declaring class (like a private member). You can use either in the same way.
To design, events should represent their namesake, i.e. events. Think of a Delegate as just the type or signature of methods. You would declare a class to have an event (of type Action), and you would add (subscribe) to that event other Actions (or methods that can be cast to an Action).
Furthermore, it is common practice to create events of a type that inherits from EventHandler<T>
An event is just a delegate with some access wrappers.
The problem with your TestB is that because the updateEvent delegate is public, ANYONE can fire the delegate, not just the class owning it.
Defining it as an Event as in your TestA, client code can only subscribe or unsubscribe to the event, they cannot fire it.
ps. You do not need your tempEvent delegates.
Anybody know why this is not possible?
If the event is just a MulticastDelegate instance you should be able to reference it in the code. the compiler says EventA can only be on left side of -= or +=.
public delegate void MyDelegate();
public event MyDelegate EventA;
public void addHandlerToEvent(MulticastDelegate md,Delegate d){
md+=d;
}
///
addHandlerToEvent(EventA,new MyDelegate(delegate(){}));
An event is not a multicast delegate, just like a property is not a field.
C#'s event syntax wraps multicast delegates to make life easier by providing syntactic sugar for adding and removing handler delegates. Your event definition would be compiled to the following:
private MyDelegate _EventA;
public event MyDelegate EventA
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_EventA = (MyDelegate)Delegate.Combine(_EventA, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_EventA = (MyDelegate)Delegate.Remove(_EventA, value);
}
}
The add and remove methods within the expanded event definition are then called when you use operator += and operator -= on the event.
This is done in order to hide the internals of the multicast delegate, but expose a simple way to implement publishing/subscribing to events. Being able to get the underlying delegate (outside of the class where it's defined) would break that intentional encapsulation.
An event is a member which binds a pair of add/remove methods(*), each of which accepts a delegate corresponding to the event signature. By default, the C# compiler will for each event auto-define a MultiCast delegate field along with add and remove members which will take the passed-in delegate and add or remove them to/from that MulticastDelegate field. The statement myEvent += someMethod;, when performed outside the class defining the event, is the required syntactic shorthand for, essentially myEvent.AddHandler(someMethod), and myEvent -= someMethod; for myEvent.RemoveHandler(someMethod), except that there is no way in C# to call the add/remove methods except using the += and -= notation.
Things are a little tricky when using the += and -= notation within the class which defines an event, since the field defined by the auto-generated event code has the same name as the event, and the behavior of myEvent += someMethod; will vary with different versions of C#.
(*) Technically a trio, since an event also includes a 'raise' method, but in practice that method is essentially never used.
Events are backed by multicast delegates, yes, but their purpose is to provide an implementation of the observer pattern, where observers (delegates in this case) may only be registered (+=) or unregistered (-=). If normal access to the backing delegate were possible outside the class itself, then it would be possible for client code to interfere with an unrelated delegate that was registered elsewhere, which could mess things up. It's also somewhat beside the point of the observer pattern to look at which other things are observing the event in question.
If you need to perform this kind of manipulation of the backing delegate, it must be done within the class (where it's treated as a regular delegate rather than an event).
You can also implement the backing delegate explicitly and provide an accessor to register/unregister with it:
private EventHandler SomeEvent;
public event EventHandler
{
add
{
SomeEvent += value;
}
remove
{
SomeEvent -= value;
}
}
This way you can provide direct access to the delegate if you need to. It's still best to provide public access to it for the purposes of subscribing/unsubscribing as an event though (rather than a raw delegate), otherwise you can run into thread-safety problems with data races on the delegates.
public delegate void SecondChangedHandler(
object clock,
TimeInfoEventArgs timeInformation);
public event SecondChangedHandler SecondChanged;
I have written a clock based on this article.
Now if i remove the event keyword i get the same result, so what does event really do?
It's compiled differently. It makes it so someone can't do
mySecondChangedHandler.SecondChanged = SomeMethod(...); //overwrite
mySecondChangedHandler.SecondChanged(...); //invoke
but only
mySecondChangedHandler.SecondChanged += SomeMethod(...);
mySecondChangedHandler.SecondChanged -= SomeMethod(...);
The event keyword creates a private delegate field, and a pair of public event accessors called add_EventName and remove_EventName. (details)
This means that writing EventName inside the class returns the delegate instance, allowing you to call or inspect the event handlers.
Outside the class, EventName doesn't really exist; all you can do is write EventName += something and EventName -= something, and the compiler will convert it into calls to the accessors. (like a property)
For more details, see this series of blog posts.
The event keyword does two things
It supplied permissions. Only the class can raise the event, however any external method can invoke the raw delegate
It provides metadata which can be used for designers and the like
The event keywords means only methods on the instance that hosts the SecondChanged field can invoke it. External attempts will fail.
The event keyword creates a pair of accessors for a delegate. These are effectively two methods (add and remove) that are called when you subscribe or unsubscribe from the event.
In your case, you're creating a "field-like event". The compiler makes a delegate behind the scenes, and allows you to subscribe and unsubscribe from it's invocation list. This means that you have all of the functionality of a delegate, but you're restricting access so that that outside world can "handle" the event, but not raise the event (invoke the delegate).
You can, however, also explicitly create your own accessors for an event, and these can do other things (though that's not typically recommended unless there is a good reason to do so).
Quote from C# lang reference about keyword event,
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class).
I have a Connection class which reads packets (commands) from a text stream and then distributes the commands to a set of handlers which process the commands as they see fit.
Eg.. Connection class reads in a command "HELLO" and then passes the command off to the handlers, where one or more handler may do something useful with the HELLO command.
Right now I use a delegate called HandleCommand which all command handlers must adhere to in order to receive the commands.
The question is, would it be more logical to use an event (eg.. CommandReceived) which the handlers could individually subscribe to? I'm having a hard time weighing up the pros and cons. it seems more wasteful to make it an event, because then an EventArgs class has to be generated for each command received.
In contrast, there is also a DisconnectCallback delegate which I strongly believe would be better as an event and will probably change.
Thank you
It seems your distributor now has to keep a list of handlers (class or delegates). That means you are duplicating the functionality of event.
The situation seems to call for events. It would decouple the components.
Concerning the 'wastefulness' of events and eventargs, see this question and stop worrying.
First - until you have evidence that it's a performance bottleneck, don't sacrifice clarity. The GC is fast and it's unlikely cleaning up a short-lived eventargs class will be the dominating performance factor here.
Anyway, If the consumers are only going to read and not modify the data, I'd make it an event. Otherwise you'd probably want to make an interface for a 'filter' that can read and modify, and pass the new value to the next one.
Events would be the most obvious approach as there are more than one command handlers.
I'm curious as to how command handlers "adhere" to a connection using delegates. You have to either simulate the event behavior by using a list of listeners or the command must actively call the handlers, what indeed compromises decoupling.
You are not required to use EventHandler or EventHandler<T> when creating an event, even though that is against Microsoft's recomendation. You can use your current delegate as the datatype for the event like so:
public event MyDelegateType EventName;
Edit:
If you are concerned about performance you can use an EventHandlerList class like so:
private EventHandlerList _events = new EventHandlerList();
private static object MyDelegateKey = new object()
public event MyDelegate EventName {
add {
_events.AddHandler(MyDelegateKey, value);
}
remove {
_events.RemoveHandler(MyDelegateKey, value);
}
}