7

I often want to write something like this:

new Form
{
    Text = "Caption",
    Controls =
    {
        new Button { Text = "Button 1", Click = (s, e) => MessageBox.Show("Button 1 Clicked"), Location = new Point(10, 10) },
        new Button { Text = "Button 2", Click = new EventHandler(Button2Clicked), Location = new Point(10, 40) },
        new Button { Text = "Button 3", Click = Button3Clicked, Location = new Point(10, 70) },
    },
}

Initializer syntax is just sugar, so why can't the compiler figure out how to generate code for an event subscription?

Gimme some sugar, baby!

When initializer syntax was invented, someone must have thought about events and rejected them. I've been trying to imagine what the rationale might have been and am coming up blank.

Is it because an event is a multi-cast object that might have more than one subscriber? No, this is an initialization process; There can be no other subscribers. [Updated] Not true, initializers are applied post-construction and an object can subscribe to its own events.

A note to Eric: I've heard the Why doesn't C# implement feature X speech. In this case, someone was already there, implementing initializers.

Updated

There seems to be contention/confusion because I used Click = in my example. The actual syntax is not relevant to the question. It could just as easily be Click += which mirrors the way you have to add a handler normally. I prefer the former because it's consistant with the rest of the initializer syntax, but ultimately I don't care, just so long as I can subscribe to an event in an initializer list.

Another Update

I do realize that adding the feature now is probably unlikely. The first issue that comes to mind is that Intellisense has to be updated. There are probably many other things that would hinder adding this feature now. My question is: Why didn't they add it in the first place. There must have been something compelling that warrented the 'nay' vote.

Tergiver
  • 14,171
  • 3
  • 41
  • 68
  • Events don't work with assignment. You have to use +=, so this syntax would be incorrect (since Click is an event) right? – Chris Pfohl Jan 20 '11 at 20:10
  • I would argue that this has nothing to do with "currently legal syntax". It's an additional syntax, specific to initializers. – Tergiver Jan 20 '11 at 20:21
  • possible duplicate of [Assigning events in object initializer](http://stackoverflow.com/questions/3993601/assigning-events-in-object-initializer) – Ben Voigt Sep 11 '13 at 15:43

4 Answers4

6

I cannot see any reason why they could not have provided this small teaspoon of sugar, I guess they just didn't!

There is already quite a lot of syntactic sugar involved in events, if simply declare an event on a class without providing your own implementation, the compiler is providing a delegate backing field for you, plus add / remove 'method' implementations. ALso, when you add an event handler, the compiler uses delegate inference, allowing you to simply point to a method, rather than create a delegate that represents the method.

Interestingly, Mono C# does allow you to add an event handler in an object initializer:

http://tirania.org/blog/archive/2009/Jul-27-1.html

Time to switch to Mono ;-)

ColinE
  • 68,894
  • 15
  • 164
  • 232
2

Try simply assigning an event:

Click = (o,e) => { <CODE> }

Doesn't work. Initializers work only with things you can directly assign like that. This is because events need to be able to notify anyone they want (you shouldn't be allowed to remove someone else's registration for that event on accident).

I'm not sure if this is their reasoning, but it works for me.

Chris Pfohl
  • 18,220
  • 9
  • 68
  • 111
  • Again I bring up the counter-argument that during initialization the event is guaranteed to be empty, but if people liked it better one could say the syntax should be `Click += (s, e) => { }`. – Tergiver Jan 20 '11 at 20:28
  • Not necessarily. If your initializer uses any methods to set a value then that method could have the side effect of subscribing the event. – Chris Pfohl Jan 20 '11 at 20:39
  • Ah, you bring up one of my favorite pet peeves. First, you have a valid point that must be considered (solved by the += syntax in my mind). Second, this is how I feel about self-subscription: http://tergiver.wordpress.com/2011/01/20/self-subscription-is-asinine/ – Tergiver Jan 20 '11 at 20:51
2

There's a big difference between fields and events. There's an excellent article here outlining the differences, but that's the answer to your question: A field can be assigned a value; an event looks like a field but is a very different beast.

Edit

From the article I linked to:

We have seen that the event keyword is a modifier for a delegate declaration that allows it to be included in an interface, constrains its invocation from within the class that declares it, provides it with a pair of customizable accessors (add and remove), and forces the signature of the delegate

Remember that event is a shortcut; behind the scenes, the compiler creates an object with add() and remove() methods. Like:

public class Button {

    public event EventHandler Click {
        void add {...}
        void remove {...}
    }

}

Perhaps this will offer some insight... :

Button btn = new Button {Click += (s, e) => MessageBox.Show("hello")};

The error message you get is "Cannot initialize type 'Button' with a collection initializer because it does not implement IEnumerable"


Still another note... if you assign the event handler from within the form, you can do this:

this.button1.Click += (s, e) => this.textBox1.Text = e.ToString();

You couldn't access form variables from the code you've created. I get where you're coming from, and I don't disagree... what you're doing could be made to work. I guess my point is that there are reasons why the decision was made not to make it work.

James King
  • 6,233
  • 5
  • 42
  • 63
  • I would argue that, from the viewpoint of initialization, there is no distinction between fields and events. – Tergiver Jan 20 '11 at 20:40
  • I appreciate the input. I have a contention with *You couldn't access form variables from the code you've created*. There are no "form variables" in the code I provided. They are not necessary. They are in fact, never necessary. The form designer gives them to you (unless you tell it not to) only as a matter of convienence. – Tergiver Jan 21 '11 at 18:41
  • 1
    Initializer syntax is used to initialize fields or properties. Properties have the same relationship to fields that events do. They are both sugar for a pair of synthesized methods or a pair of methods provided by the programmer. So I don't see a field vs. event comparison as valid. Your error message is also not insightful, because brace initialization has two meanings depending on context. The compiler decided you were trying to do collection initialization but that also wasn't valid. – Justin Aquadro Jul 03 '13 at 20:36
1

Yep, should be part of the language!

But, here's a tricky workaround that lets you subscribe to events within an initializer list...

public class TestClass
{
    public class MyButton : Button
    {
        public EventHandler ClickSubscriber
        {
            get { return null; }
            set { Click += value; }
        }
    }

    public static void RunTest()
    {
        new Form
            {
                Text = "Caption",

                Controls =
                    {
                        new MyButton 
                            { 
                                ClickSubscriber = (s, e) => 
                                     MessageBox.Show("Button 1 Clicked"), 
                            },
                    },
            };
    }        
}
James
  • 1,973
  • 1
  • 18
  • 32