very simple delegate musing

2020-04-21 03:45发布

问题:

Sometimes the simplest questions make me love C/C++ and C# more and more.

Today sitting on the bus musing aout delegates I remembered reading somwhere you don't need to use the new keyword when instaniating a new delegate.

For example:

    public static void SomeMethod(string message)
    {
      ...
    }

    ...


   public delegate void TestDelgate(string message); //Define a delegate

    ...........

   //create a new instance ..METHOD 1
   TestDelgate t = new TestDelgate(SomeMethod);  

   //OR another way to create a new instance ..METHOD 2
   TestDelgate t = SomeMethod;   //create a new instance ..METHOD 2

So todays questions are

  1. What happens under the hood in method 2. Does the compiler expand method 2 into method 1, hence writing TestDelgate t = SomeMethod; is just a shortcut for TestDelgate t = new TestDelgate(SomeMethod);, or is there another reason for the exsitence of method 2

  2. Do you guys think method 1 or method 2 is better for readability (this is a subjective question, but I'd just like to get a unscientific feel of general opinion of stackoverflow :-))

回答1:

It is sugar. The kind of sugar that really comes in handy when you have to write this:

 someObj.Test -= new TestDelegate(SomeMethod);

What? You have to use the new keyword to remove an event handler. Yes, you do. The VB.NET team really pained about this, they decided for a completely different syntax:

 RemoveHandler someObj.Test, AddressOf SomeMethod


Even the above C# statement is sugar, the real code looks like this:

 someObj.Test.remove(new TestDelegate(this, SomeMethod));

Where "remove" is the accessor function for an event. And "this" is required to initialize the Delegate.Target property. Now it is obvious that it is actually a method call and using the new keyword suddenly makes sense again. Hiding "this" has some disadvantages too, it isn't obvious anymore that an event subscription will prevent an object from getting garbage collected.



回答2:

Yes, method 2 is just shorthand for method 1 - at least in the case of using a method group. You can also use:

TestDelegate t = new TestDelegate(someExistingDelegate);

which allows for variance (not just the generic variance from C# 4) and creates a separate delegate... but that's rarely useful.

Personally I go with option 2... method group conversions are very handy like that. In particular it makes event wiring simpler:

button.Click += LoadDocument;

instead of

button.Click += new EventHander(LoadDocument);

The latter just has extra fluff - the former has better information density. It's also important when you're passing the delegate as a method argument. For example, compare:

observable.Subscribe(new Action<string>(Console.WriteLine));

with

observable.Subscribe(Console.WriteLine);

Unless there's any ambiguity in terms of which delegate type you actually want to convert the method group to, I just use the implicit conversion.



回答3:

Under-the-hood, your 2 methods are exactly the same. It is just the compiler being smart about what you want to do. This little feature is called delegate inference and was added in C#2.0.

I think you should use #2, and take advantage of delegate inference. They compile to the same IL, and option #2 is shorter and more concise. It is easier to read and understand the meaning of the code, because there is less noise.

This syntax is also supported for events.



回答4:

  1. Yes they are compiled into the same thing.

  2. I prefer #2. Just because it is shorter and not so clumsy. You already know that it is a TestDelegate due to defining that before. So why write it again?



回答5:

  1. It's just syntatic sugar for the explicit delegate creation. This was introduced in C# 2.0. You may have noticed that Visual Studio 2008 still generates the old-style (method 1) syntax if you ask it to create an event handler; I always replace it manually by the new syntax.

  2. I normally prefer the shorter form in method 2. I used method 1 only once: with a delegate that was to be invoked from native code, and therefore could not be garbage-collected. I wanted to be very explicit about creating and assigning it.



回答6:

Under the hood both statements create delegate object and pass to parameters to ctor: address of method and reference to this. second is just syntax sugar.



回答7:

One advantage of the 'new' syntax is that it informed the programmer that a new object was being allocated; if it would be desirable to avoid repeatedly creating new identical delegates, one could pull the delegate out to a field. I know that in fact one is allowed to use one delegate to subscribe and another to unsubscribe, but to me that feels wrong. Storing to a field the delegate used to subscribe, and then unsubscribing using that same delegate feels cleaner. Cleaner still, IMHO, would have been if the act of subscribing would have returned a MethodInvoker which, when called, would unsubscribe (in which case an "event" would simply be a function that accepted an EventHandler and returned a MethodInvoker), but that's not how .net events work.



标签: c# delegates