views:

232

answers:

7

Quote from: http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx

"Invoking an event can only be done from within the class that declared the event."

I am puzzled why there is such restriction. Without this limitation I would be able to write a class (one class) which once for good manages sending the events for a given category -- like INotifyPropertyChanged.

With this limitation I have to copy and paste the same (the same!) code all over again. I know that designers of C# don't value code reuse too much (*), but gee... copy&paste. How productive is that?

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

In every class changing something, to the end of your life. Scary!

So, while I am reverting my extra sending class (I am too gullible) to old, "good" copy&paste way, can you see

what terrible could happen with the ability to send events for a sender?

If you know any tricks how to avoid this limitation -- don't hesitate to answer as well!

(*) with multi inheritance I could write universal sender once for good in even clearer manner, but C# does not have multi inheritance

Edits

The best workaround so far

Introducing interface

public interface INotifierPropertyChanged : INotifyPropertyChanged
{
    void OnPropertyChanged(string property_name);
}

adding new extension method Raise for PropertyChangedEventHandler. Then adding mediator class for this new interface instead of basic INotifyPropertyChanged.

So far it is minimal code that let's send you message from nested object in behalf of its owner (when owner required such logic).

THANK YOU ALL FOR THE HELP AND IDEAS.

Edit 1

Guffa wrote:

"You couldn't cause something to happen by triggering an event from the outside,"

It is interesting point, because... I can. It is exactly why I am asking. Take a look.

Let's say you have class string. Not interesting, right? But let's pack it with Invoker class, which send events every time it changed.

Now:

class MyClass : INotifyPropertyChanged
{
    public SuperString text { get; set; }
}

Now, when text is changed MyClass is changed. So when I am inside text I know, that if only I have owner, it is changed as well. So I could send event on its behalf. And it would be semantically 100% correct.

Remark: my class is just a bit smarter -- owner sets if it would like to have such logic.

Edit 2

Idea with passing the event handler -- "2" won't be displayed.

public class Mediator
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string property_name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property_name));
    }

    public void Link(PropertyChangedEventHandler send_through)
    {
        PropertyChanged += new PropertyChangedEventHandler((obj, args) => {
            if (send_through != null)
                send_through(obj, args);
        });
    }

    public void Trigger()
    {
        OnPropertyChanged("hello world");
    }
}
public class Sender
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Sender(Mediator mediator)
    {
        PropertyChanged += Listener1;
        mediator.Link(PropertyChanged);
        PropertyChanged += Listener2;

    }
    public void Listener1(object obj, PropertyChangedEventArgs args)
    {
        Console.WriteLine("1");
    }
    public void Listener2(object obj, PropertyChangedEventArgs args)
    {
        Console.WriteLine("2");
    }
}

    static void Main(string[] args)
    {
        var mediator = new Mediator();
        var sender = new Sender(mediator);
        mediator.Trigger();

        Console.WriteLine("EOT");
        Console.ReadLine();
    }

Edit 3

As an comment to all argument about misuse of direct event invoking -- misuse is of course still possible. All it takes is implementing the described above workaround.

Edit 4

Small sample of my code (end use), Dan please take a look:

public class ExperimentManager : INotifierPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string property_name)
    {
        PropertyChanged.Raise(this, property_name);
    }


    public enum Properties
    {
        NetworkFileName,
        ...
    }

    public NotifierChangedManager<string> NetworkFileNameNotifier;
    ...

    public string NetworkFileName 
    { 
         get { return NetworkFileNameNotifier.Value; } 
         set { NetworkFileNameNotifier.Value = value; } 
    }

    public ExperimentManager()
    {
        NetworkFileNameNotifier = 
            NotifierChangedManager<string>.CreateAs(this, Properties.NetworkFileName.ToString());
        ... 
    }
+5  A: 

Think about it for a second before going off on a rant. If any method could invoke an event on any object, would that not break encapsulation and also be confusing? The point of events is so that instances of the class with the event can notify other objects that some event has occurred. The event has to come from that class and not from any other. Otherwise, events become meaningless because anyone can trigger any event on any object at any time meaning that when an event fires, you don't know for sure if it's really because the action it represents took place, or just because some 3rd party class decided to have some fun.

That said, if you want to be able to allow some sort of mediator class send events for you, just open up the event declaration with the add and remove handlers. Then you could do something like this:

public event PropertyChangedEventHandler PropertyChanged {
    add {
        propertyChangedHelper.PropertyChanged += value;
    }
    remove {
        propertyChangedHelper.PropertyChanged -= value;
    }
}

And then the propertyChangedHelper variable can be an object of some sort that'll actually fire the event for the outer class. Yes, you still have to write the add and remove handlers, but it's fairly minimal and then you can use a shared implementation of whatever complexity you want.

siride
It would be confusing if you use it all the time--but the point is that nobody forces you to use it (quite contrary to current state). It is similar to operator overloading in Java--it is (or was?) forbidden because somebody somewhere could overload it in a bad manner. And for that reason **all** developers are not allowed to do it. I didn't quite get the mediator pattern here -- I have a class which inherits from INotifyPropertyChanged already (and it has to be that way), the mediator (I wrote it before I post the question) is inable to invoke the event for this class, because it is external.
macias
I don't think it's equivalent to that. There's never a good reason for a class to invoke an other object's events. That's from the meaning of an event. In other words, I don't think it's possible for that ever to be done correctly, at least from a semantics point of view. With operator overloading, at least, it actually makes sense in many cases.
siride
I was being sloppy with my terminology. It's not necessarily a mediator. The point is that you have some class that implements property change notification business. This is as an alternative to multiple inheritance (using composition instead).
siride
Yes, that is my case -- so it is correct (in sense of workflow logic), yet I cannot model it.
macias
It's not correct. Sending an event from another class is never correct. If your workflow logic requires that, then you need to rethink your workflow or your implementation or both.
siride
Did you read my "edit"? It is 100% percent correct because I asked nested object "please, send the event in behalf of me". IOW: when you consider multi-part object, the state of the object is changed when any part is changed (consider tree structure). If a node knows the owner (tree) it is correct to send event from node "hey, the tree is changed".
macias
I know you think that sounds reasonable, but the semantics are still wrong. The nodes are changing, so they can send events about that, and the tree can listen for those events and then in turn send its own event saying that it changed. But neither should send events on behalf of the other. I'm sorry, but you'll have to accept that that is never correct and that's why MS made it hard to do.
siride
+4  A: 

Allowing anyone to raise any event puts us in this problem:

@Rex M: hey everybody, @macias just raised his hand!

@macias: no, I didn't.

@everyone: too late! @Rex M said you did, and we all took action believing it.

This model is to protect you from writing applications that can easily have invalid state, which is one of the most common sources of bugs.

Rex M
macias
@macias it doesn't mean the state is invalid, it is just opens the door to making it much more *easy* for you to write code where the state is invalid, with very little benefit in exchange.
Rex M
macias
@macias it sounds like - as you said at the end of your question - multiple inheritance might be a good solution for this problem. Allowing outside callers to raise events, however, is not.
Rex M
Yes, it would be much better -- because in such case the sender would send its own messages.
macias
+1  A: 

First of all I must say, events are actually meant to be invoked from within the object only when any external eventhandler is attached to it.

So basically, the event gives you a callback from an object and gives you a chance to set the handler to it so that when the event occurs it automatically calls the method.

This is similar of sending a value of variable to a member. You can also define a delegate and send the handler the same way. So basically its the delegate that is assigned the function body and eventually when the class invokes the event, it will call the method.

If you dont want to do stuffs like this on every class, you can easily create an EventInvoker which defines each of them, and in the constructor of it you pass the delegate.

public class EventInvoker
{
   public EventInvoker(EventHandler<EventArgs> eventargs)
   {
      //set the delegate. 
   } 

   public void InvokeEvent()
   {
        // Invoke the event. 
   }
}

So basically you create a proxy class on each of those methods and making this generic will let you invoke events for any event. This way you can easily avoid making call to those properties every time.

abhishek
Thank you, but what I can do with this Invoker class? As I mentioned C# does not have multi inheritance, so in 99% cases I cannot inherit from it (like MyWindow in WPF which inherits from Window already), and without it I am not able to invoke an event from Invoker.
macias
No you dont inherit it, rather you create object of the class and use Event Accessor to pass the delegate to that class.
abhishek
If I read you right, it won't work. When you pass the list of listeners, all you get are the listeners at the moment of the passing them -- any later alteration won't be visible. See edit2.
macias
How about building an Observer. Just as it does with Reactive Framework.
abhishek
+1  A: 

Events are intended for being notified that something has happened. The class where event is declared takes care of triggering the event at the right time.

You couldn't cause something to happen by triggering an event from the outside, you would only cause every event subscriber to think that it had happened. The correct way to make something happen is to actually make it happen, not to make it look like it happened.

So, allowing events to be triggered from outside the class can almost only be misused. On the off chance that triggering an event from the outside would be useful for some reason, the class can easily provide a method that allows it.

Guffa
I cause something to happen by triggering an event from the outside. See edits.
macias
@macias: No, triggering a PropertyChanged event doesn't cause the property to change. You are just trying to move the responsibility for triggering the event out of the class, which only makes the code harder to follow.
Guffa
So let's say that you made a `Button` class that raises a `Presssed` event when somebody clicks on it. Why is it bad to be able to create a subclass of `Button` that raises the `Pressed` event when somebody presses the Enter key?
Gabe
@Gabe: That would be OK as the class is a `Button`. Then you can follow the practice in the framework and create a method `protected virtual void OnPressed(EventArgs e)` that raises the event.
Guffa
Guffa: But that `OnPressed` function is only necessary because a subclass can't raise an event from its base class. I think the existence of the `OnXXX` convention is proof that there is a good use for raising an event from outside its class.
Gabe
A: 

Hi

My thoughts

you don't need to copy below code over and over again.

 public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged(string name) 
    { 
        if (PropertyChanged != null) 
        { 
            PropertyChanged(this, new PropertyChangedEventArgs(name)); 
        } 
    } 

i am assuming that you are working on a WPF application.

use MVVM pattern

Where you implement InotifyPropertyChanged in a ViewModelBase Class.

if you are not working on WPF application and you are using INotifyPropertyChanged interface that means , you need to update some listners based upon some condition so to avoid duplicate code , you can use ObserverPattern

saurabh
WPF was just an example. Observer pattern is exactly the events in C#, so this leads us in circle to nowhere.
macias
+2  A: 

I think you're misunderstanding the restriction. What this is trying to say is that only the class which declared the event should actually cause it to be raised. This is different than writing a static helper class to encapsulate the actual event handler implementation.

A class A that is external to the class which declares the event B should not be able to cause B to raise that event directly. The only way A should have to cause B to raise the event is to perform some action on B which, as a result of performing that action raises the event.

In the case of INotifyPropertyChanged, given the following class:

public class Test : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   private string name;

   public string Name
   {
      get { return this.name; }
      set { this.name = value; OnNotifyPropertyChanged("Name"); }
   }

   protected virtual void OnPropertyChanged(string name)
   {
       PropertyChangedEventHandler  temp = PropertyChanged;
       if (temp!= null)
       {
          temp(this, new PropertyChangedEventArgs(name));
       }
   }
}

The only way for a class consuming Test to cause Test to raise the PropertyChanged event is by setting the Name property:

public void TestMethod()
{
    Test t = new Test();
    t.Name = "Hello"; // This causes Test to raise the PropertyChanged event
}

You would not want code that looked like:

public void TestMethod()
{
    Test t = new Test();
    t.Name = "Hello";
    t.OnPropertyChanged("Name");
}

All of that being said, it is perfectly acceptable to write a helper class which encapsualtes the actual event handler implementation. For example, given the following EventManager class:

/// <summary>
/// Provides static methods for event handling. 
/// </summary>
public static class EventManager
{
    /// <summary>
    /// Raises the event specified by <paramref name="handler"/>.
    /// </summary>
    /// <typeparam name="TEventArgs">
    /// The type of the <see cref="EventArgs"/>
    /// </typeparam>
    /// <param name="sender">
    /// The source of the event.
    /// </param>
    /// <param name="handler">
    /// The <see cref="EventHandler{TEventArgs}"/> which 
    /// should be called.
    /// </param>
    /// <param name="e">
    /// An <see cref="EventArgs"/> that contains the event data.
    /// </param>
    public static void OnEvent<TEventArgs>(object sender, EventHandler<TEventArgs> handler, TEventArgs e)
         where TEventArgs : EventArgs
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler<TEventArgs> tempHandler = handler;

        // Event will be null if there are no subscribers
        if (tempHandler != null)
        {
            tempHandler(sender, e);
        }
    }

    /// <summary>
    /// Raises the event specified by <paramref name="handler"/>.
    /// </summary>
    /// <param name="sender">
    /// The source of the event.
    /// </param>
    /// <param name="handler">
    /// The <see cref="EventHandler"/> which should be called.
    /// </param>
    public static void OnEvent(object sender, EventHandler handler)
    {
        OnEvent(sender, handler, EventArgs.Empty);
    }

    /// <summary>
    /// Raises the event specified by <paramref name="handler"/>.
    /// </summary>
    /// <param name="sender">
    /// The source of the event.
    /// </param>
    /// <param name="handler">
    /// The <see cref="EventHandler"/> which should be called.
    /// </param>
    /// <param name="e">
    /// An <see cref="EventArgs"/> that contains the event data.
    /// </param>
    public static void OnEvent(object sender, EventHandler handler, EventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler tempHandler = handler;

        // Event will be null if there are no subscribers
        if (tempHandler != null)
        {
            tempHandler(sender, e);
        }
    }
}

It's perfectly legal to change Test as follows:

public class Test : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   private string name;

   public string Name
   {
      get { return this.name; }
      set { this.name = value; OnNotifyPropertyChanged("Name"); }
   }

   protected virtual void OnPropertyChanged(string name)
   {
       EventHamanger.OnEvent(this, PropertyChanged, new PropertyChangedEventArgs(name));
   }
}
Scott Dorman
Your use of those `tempHandler` local variables in the `OnEvent` overloads is redundant, you know. There's no such thing as a race condition that reassigns the variables copied locally to the stack!
Dan Tao
Thank you for the code. However you have still this method OnPropertyChanged in your Rest class. Look at the line: "this.name = value". Do the name changed? YES. So at this point you know the Test changed. The idea is to send event from "name" through "Test" to its listeners.
macias
@macias: Behavior like what you just described is actually not only *disallowed*, it is **completely impossible** since the `name` *variable* is not the same as the *object* to which `name` points. That is to say, the object knows nothing about the variable (how could it?) -- see my update. (There's still something *like* what you're asking that could *theoretically* be possible, though it is currently not legal. That is what I'm talking about in my answer.)
Dan Tao
@Dan, well, it depends what class you use for name. In my case it is string with notifier manager built in.
macias
@Dan Tao: it's not redundant at all, actually. The point is that if he didn't use a local variable, and just tested the field before invoking it, there would be a race condition (between testing the field and then invoking it). By copying the field to a local variable, it will no longer matter whether the field changes because you can just use the local copy, which you rightly point out, cannot be changed.
siride
@siride: It **is** redundant. `handler` is **already a local variable** because it has been passed as a parameter to a method of this `EventManager` class. The original sender's private delegate field could be changed to `null` and it would not affect the `handler` variable already living in the scope of an `EventManager.OnPropertyChanged` call (for instance); so there's no race condition to prevent.
Dan Tao
@Dan Tao: d'oh! I missed that parameter since I need to scroll over to see it.
siride
+1  A: 

Update

OK, before we go any further, we definitely need to clarify a certain point.

You seem to want this to happen:

class TypeWithEvents
{
    public event PropertyChangedEventHandler PropertyChanged;

    // You want the set method to automatically
    // raise the PropertyChanged event via some
    // special code in the EventRaisingType class?
    public EventRaisingType Property { get; set; }
}

Do you really want to be able to write your code just like this? This is really totally impossible -- at least in .NET (at least until the C# team comes up with some fancy new syntactic sugar specifically for the INotifyPropertyChanged interface, which I believe has actually been discussed) -- as an object has no notion of "the variables that have been assigned to me." In fact there is really no way to represent a variable using an object at all (I suppose LINQ expressions is a way, actually, but that's a totally different subject). It only works the opposite way. So let's say you have:

Person x = new Person("Bob");
x = new Person("Sam");

Does "Bob" know x just got assigned to "Sam"? Absolutely not: the variable x just pointed to "Bob", it never was "Bob"; so "Bob" doesn't know or care one lick about what happens with x.

Thus an object couldn't possibly hope to perform some action based on when a variable pointing to it gets changed to point at something else. It would be as if you wrote my name and address on an envelope, and then you erased it and wrote somebody else's name, and I somehow magically knew, @macias just changed the address on an envelope from mine to someone else's!

Of course, what you can do is modify a property so that its get and set methods modify a different property of a private member, and link your events to an event supplied by that member (this is essentially what siride has suggested). In this scenario it would be kind of reasonable to desire the functionality you're asking about. This is the scenario that I have in mind in my original answer, which follows.


Original Answer

I wouldn't say that what you're asking for is just flat-out wrong, as some others seem to be suggesting. Obviously there could be benefits to allowing a private member of a class to raise one of that class's events, such as in the scenario you've described. And while saurabh's idea is a good one, clearly, it cannot always be applied since C# lacks multiple inheritance*.

Which gets me to my point. Why doesn't C# allow multiple inheritance? I know this might seem off-topic, but the answers to this and that question are the same. It isn't that it's illegal because it would "never" make sense; it's illegal because there are simply more cons than pros. Multiple inheritance is very hard to get right. Similarly, the behavior you are describing would be very easy to abuse.

That is, yes, the general case Rex has described makes a pretty good argument against objects raising other objects' events. The scenario you've described, on the other hand -- the constant repetition of boilerplate code -- seems to make something of a case in favor of this behavior. The question is: which consideration should be given greater weight?

Let's say the .NET designers decided to allow this, and simply hope that developers would not abuse it. There would almost certainly be a lot more broken code out there where the designer of class X did not anticipate that event E would be raised by class Y, way off in another assembly. But it does, and the X object's state becomes invalid, and subtle bugs creep in everywhere.

What about the opposite scenario? What if they disallowed it? Now of course we're just considering reality, because this is the case. But what is the huge downside here? You have to copy and paste the same code in a bunch of places. Yes, it's annoying; but also, there are ways to mitigate this (such as saurabh's base class idea). And the raising of events is strictly defined by the declaring type, always, which gives us much greater certainty about the behavior of our programs.

So:

EVENT POLICY                  | PROS                | CONS
------------------------------+---------------------+-------------------------
Allowing any object to raise  | Less typing in      | Far less control over
another object's event        | certain cases       | class behavior, abun-
                              |                     | dance of unexpected 
                              |                     | scenarios, proliferation
                              |                     | of subtle bugs
                              |                     |
------------------------------------------------------------------------------
Restricting events to be only | Much better control | More typing required
raised by the declaring type  | of class behavior,  | in some cases
                              | no unexpected       |
                              | scenarios, signifi- |
                              | cant decrease in    |
                              | bug count           |

Imagine you're responsible for deciding which event policy to implement for .NET. Which one would you choose?

*I say "C#" rather than ".NET" because I'm actually not sure if the prohibition on multiple inheritance is a CLR thing, or just a C# thing. Anybody happen to know?

Dan Tao
The only problem with your table is (THANK YOU) that you are mixing people. Yes. I am punished because Joe Doe does not know how to write program. I strongly support the idea "everything should be doable, easy things easily, odd ones -- with difficulty". Forbidding something in advance is slight sign of vanity, because from time perspective it means "we predicted every possible use". I don't believe in such vast anticipation. And in regard to this issue -- I didn't use many dangerous features ($_ in Perl, anyone) and I wouldn't be addict for this too :-)
macias
@macias: Firstly, "mixing people" is unavoidable, is it not? Every developer cannot have his/her own programming language with its own set of rules. Secondly, your philosophy for what a programming language should be is not the same as the C# philosophy. Once again the question comes down to pros and cons. By being widely accessible and feature-rich while restricting usage in ways that are designed to protect the average (sometimes careless) developer, C# has become an incredibly popular and useful language. They could've made it less rigid, and more buggy programs would've been written.
Dan Tao
Popularity has nothing to do with quality. The second, when you look at C# framework you will notice that despite the hype about being statically typed it is actually very dynamic languages, magical literal are flying around all the time (for in example in XAML). But triggering change events are good example as well. There is no nameof(MyProperty) only "MyProperty" (yes, I know the workaround), so IMHO C# is far, far away from being solid, bullet-proof language.
macias
Now, about the update -- the last paragraph of your update is EXACTLY my case. Maybe I add it just for the record. Please, see edit 4 -- I hope we both think about the same thing.
macias
@macias: In response to your first comment, I really think you're getting it backwards. Quality is precisely what these restrictions are in place to *improve* by eliminating scenarios that are likely to lead to bugs. Suppose I had some bizarre genetic condition where I could drink an unlimited amount of alcohol and still be a completely safe driver. It would be absurd for me to argue, "This law against drunk driving is a bad law! **I** can drive just fine after drinking; don't punish me for what others shouldn't do!" By making it illegal, a ton of fatal accidents are prevented.
Dan Tao
@macias: On the other hand, as my table is meant to illustrate, the opposite scenario brings with it not *nearly* enough benefit to counteract the associated costs. To continue my analogy: what if they legalized driving while intoxicated? On the plus side, I would no longer be inconvenienced when I decided to drive myself home from a bar. The downside would be that there would suddenly be a lot more car accidents, and a lot of people dying. In the case of .NET event invocation, I really think it's a similarly *unbalanced* trade off. Clearly you disagree with me; but I think that's the idea.
Dan Tao
macias
@macias: there will always be boilerplate. Even with a general sender, you'd have to write code in each property. Now, one option is to use PostSharp to weave in code that sends the event whenever any property is changed. You'd only have to do that once and then specify which classes you want it to apply to. To be perfectly honest, this may be the best solution for you.
siride
@Siride, now I don't have to write code for each property. I already skipped that -- see my edits, I embed each property in sender class, which is simply notifier. So I create it, and it does the rest. Btw. it is really odd, how WPF is designed that it listens to source container for change, but it ignores the source itself.
macias
Dan Tao
@Dan, as you know there is no unbreakable protection -- it applies to hardware, software, and language too. No matter what language you consider there will be always a moron, who would write complete mess. I prefer languages that helps **me** keep **my** code clean, and warn me about dangers but allow me do this. For a wise developer, warning is enough, but with prohibiting this or that usage you are limiting the potential of the possible expressions. We mature for a reason, keeping it "safe" (by prohibiting things) is making a a toy, not a tool.
macias
@macias: Yes, but much more common than *morons* are actually *pretty smart developers* who nonetheless misunderstand how something works or simply don't care that a certain way of doing things is inadvisable, because it does what they want and they just want to move forward. Neither C# nor any other language is going to protect the world from morons; but it can help those developers who might otherwise do something iffy (e.g., raising another object's event) by having mechanisms in place which strongly promote better strategies.
Dan Tao
@macias: As for your case, this hardly even seems relevant anymore as the solution you seem to have settled upon in your question is also the most obvious one: have a type expose a public method that basically *amounts to* raising a specific event. I mean, that's pretty much all you wanted to do anyway, right? So is C# really even keeping you from doing what you want anymore? It doesn't seem like it.
Dan Tao