|
tech
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Events with accessorsto the way a property is declared: private EventHandler myEvent; public event EventHandler MyEvent { add { lock (this) { myEvent += value; } } remove { lock (this) { myEvent -= value; } } } Here it is explicitly stated that when handlers are added to the event, they should be added to the delegate _myEvent, and likewise for removal. When the event is *raised*, however, I don't understand where this tells the application to look at _myEvent for the handler(s) to be called. The add and remove accessors both correspond to the set accessor in a property declaration, but there isn't anything that corresponds to the get accessor. The code above seems similar to private int number; public int Number { set { number = value; } } and then expecting that when the statement int x = Number; is executed, the application will know to get the required value from the private field number, when I haven't included a get accessor to make it so. What am I missing? Harlan Messinger <hmessinger.removet***@comcast.net> wrote:
> I've found information on an explicit way of declaring events, similar <snip>> to the way a property is declared: > Here it is explicitly stated that when handlers are added to the event, Well, you have to write the code to raise the event yourself. If you > they should be added to the delegate _myEvent, and likewise for removal. > When the event is *raised*, however, I don't understand where this tells > the application to look at _myEvent for the handler(s) to be called. try to call MyEvent() it will fail to compile - you need to call myEvent(). > The add and remove accessors both correspond to the set accessor in a And that's deliberate - clients of the class don't get to find out > property declaration, but there isn't anything that corresponds to the > get accessor. what's subscribed - they just get to subscribe and unsubscribe. Only the class implementing the event knows how to raise it. See http://pobox.com/~skeet/csharp/events.html for more info. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk Jon Skeet [C# MVP] wrote:
Show quote > Harlan Messinger <hmessinger.removet***@comcast.net> wrote: Doh! That's the piece that eluded me. And that, I think, answers the >> I've found information on an explicit way of declaring events, similar >> to the way a property is declared: > > <snip> > >> Here it is explicitly stated that when handlers are added to the event, >> they should be added to the delegate _myEvent, and likewise for removal. >> When the event is *raised*, however, I don't understand where this tells >> the application to look at _myEvent for the handler(s) to be called. > > Well, you have to write the code to raise the event yourself. If you > try to call MyEvent() it will fail to compile - you need to call > myEvent(). question that led me to this one: I thought it was rather dumb (though I suppose there must be some, probably security-related, reason) and certainly annoying that a "real" event's delegate is private rather than protected, preventing a derived class from raising an event declared in a base class. Yes, I know it's a field, therefore ordinarily private, but this seemed like a good reason to have an exception. > Heh, that redirects to the page I took my code sample from (except that >> The add and remove accessors both correspond to the set accessor in a >> property declaration, but there isn't anything that corresponds to the >> get accessor. > > And that's deliberate - clients of the class don't get to find out > what's subscribed - they just get to subscribe and unsubscribe. Only > the class implementing the event knows how to raise it. > > See http://pobox.com/~skeet/csharp/events.html for more info. I removed the initial underscores). Harlan Messinger <hmessinger.removet***@comcast.net> wrote:
> > Well, you have to write the code to raise the event yourself. If you Well, you can certainly make it protected if you really want to. It's > > try to call MyEvent() it will fail to compile - you need to call > > myEvent(). > > Doh! That's the piece that eluded me. And that, I think, answers the > question that led me to this one: I thought it was rather dumb (though I > suppose there must be some, probably security-related, reason) and > certainly annoying that a "real" event's delegate is private rather than > protected, preventing a derived class from raising an event declared in > a base class. Yes, I know it's a field, therefore ordinarily private, > but this seemed like a good reason to have an exception. just a normal field. Personally, I wouldn't - I'd create a protected method called OnMyEvent() which raises the event, and keep the detail private. Then again, I don't often have events in classes which other classes derive from - I use inheritance fairly sparingly. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk Jon Skeet [C# MVP] wrote:
Show quote > Harlan Messinger <hmessinger.removet***@comcast.net> wrote: It's just that I'm tired already at having to define so many things for >>> Well, you have to write the code to raise the event yourself. If you >>> try to call MyEvent() it will fail to compile - you need to call >>> myEvent(). >> Doh! That's the piece that eluded me. And that, I think, answers the >> question that led me to this one: I thought it was rather dumb (though I >> suppose there must be some, probably security-related, reason) and >> certainly annoying that a "real" event's delegate is private rather than >> protected, preventing a derived class from raising an event declared in >> a base class. Yes, I know it's a field, therefore ordinarily private, >> but this seemed like a good reason to have an exception. > > Well, you can certainly make it protected if you really want to. It's > just a normal field. Personally, I wouldn't - I'd create a protected > method called OnMyEvent() which raises the event, and keep the detail > private. each event. The corresponding handler, the corresponding delegate, the corresponding event arguments--and now, yet another entity so that I can define an Event in an abstract base class for each derived class to raise when appropriate. I really don't see why events declared in the usual way couldn't have been set up for raising by derived classes, despite their encapsulation of the private delegate. I mean, that's the point of the encapsulation--the derived class doesn't know about it or have access to it, but should be able to use the public wrapper that relies on it, just as a public or protected property Number can be called by a derived class method even though it relies on a private field called number. > Then again, I don't often have events in classes which other classes Well, I've got interfaces IProcessMonitor and IMonitoredProcess designed > derive from - I use inheritance fairly sparingly. to work together, to generalize the concept of launching a process from a main window and displaying a progress window that is loosely connected to it: public interface IMonitoredProcess { event ProgressUpdateHandler ProgressUpdated; event ProcessStatusHandler ProcessStatusUpdated; event ProcessEndedHandler Ended; void Run(); void Cancel(object source, EventArgs e); int ItemCount { get ; } } public interface IProcessMonitor { event EventHandler CancelRequested; void SetCount(int count); void ProgressUpdated(object source, ProgressUpdateEventArgs e); void ProcessStatusUpdated(object source, ProcessStatusEventArgs e); void ProcessEnded(object source, ProcessEndedEventArgs e); } I've got a Windows application that uses a single screen to collect inputs, including a list of files, and then lets the user choose from among several operations that can be applied file by file (comparing the versions of each file at two different locations by date or byte-by-byte, copying the files from one location to another). The button click leads to a routine that creates a processing object implementing IMonitoredProcess and a progress monitoring object and wires their respective events and methods together before launching the process asynchronously and showing the progress window that implements IProcessMonitor. I created an abstract class, AbstractFileProcessor, that implements IMonitoredProcess and does most of the work that will always need to be done: validation of inputs, iteration through the list of files, raising progress events as the iteration proceeds. There is an abstract method, ProcessOneFile. The override for this in each derived class is responsible for the custom operation. It needs to be able to raise ProcessStatusUpdate messages, including result messages ("file in location 2 is newer") and error messages. I could have a single class with multiple methods and choose one method to call conditionally, but I preferred the architecture I'd come up with where each button click handler creates the appropriate processing object, after which all the invoking code is the same. button1_OnClick(...) LaunchProcess(new ThisDerivedClass(...)); ... button2_OnClick(...) LaunchProcess(new ThatDerivedClass(...)); ... LaunchProcess initializes the processing object and creates and initializes the progress window and then starts the former and shows the latter. I figured that was the neatest approach. But with so much code bloat wrapped around each event, it's frustrating. Harlan Messinger <hmessinger.removet***@comcast.net> wrote:
Show quote > > Well, you can certainly make it protected if you really want to. It's What do you mean by "the usual way"? As a field-like event? You can > > just a normal field. Personally, I wouldn't - I'd create a protected > > method called OnMyEvent() which raises the event, and keep the detail > > private. > > It's just that I'm tired already at having to define so many things for > each event. The corresponding handler, the corresponding delegate, the > corresponding event arguments--and now, yet another entity so that I can > define an Event in an abstract base class for each derived class to > raise when appropriate. > > I really don't see why events declared in the usual way couldn't have > been set up for raising by derived classes, despite their encapsulation > of the private delegate. still do that by explicitly providing a protected method which raises the event... but if it *automatically* made the backing field protected, with no way of making it private, that would be a really bad idea. > I mean, that's the point of the A derived class can use the event in exactly the same way as a > encapsulation--the derived class doesn't know about it or have access to > it, but should be able to use the public wrapper that relies on it, just > as a public or protected property Number can be called by a derived > class method even though it relies on a private field called number. different class can - but it can't get at the private implementation, just as a public or protected property prevents you from getting at the implementation. There's no disparity here. <snip> > LaunchProcess initializes the processing object and creates and I view it the other way: you're going to have nullity checking for the > initializes the progress window and then starts the former and shows the > latter. I figured that was the neatest approach. But with so much code > bloat wrapped around each event, it's frustrating. event, right? So you need to write code for: ProgressUpdateHandler handler = ProgressUpdated; if (handler != null) { handler(...); } Now, if you encapsulate that in an protected OnProgressUpdated method, you've got the "overhead" of declaring a method, but that nullity check is only implemented once. If you started raising the event directly from each derived class, you'd have the bloat of that nullity check everywhere. Admittedly one workaround the nullity check is to provide a no-op handler as the initial value, so you know it'll never be null... something like this: public event ProgressUpdateHandler ProgressUpdated = delegate {}; -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk |
|||||||||||||||||||||||