Initializing events with initializer syntax

前端 未结 4 1120
情书的邮戳
情书的邮戳 2020-12-07 01:57

I often want to write something like this:

new Form
{
    Text = \"Caption\",
    Controls =
    {
        new Button { Text = \"Button 1\", Click = (s, e) =         


        
相关标签:
4条回答
  • 2020-12-07 02:29

    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.

    0 讨论(0)
  • 2020-12-07 02:38

    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"), 
                                },
                        },
                };
        }        
    }
    
    0 讨论(0)
  • 2020-12-07 02:46

    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 ;-)

    0 讨论(0)
  • 2020-12-07 02:51

    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.

    0 讨论(0)
提交回复
热议问题