tags:

views:

36

answers:

3

Like most devs, have been using delegates for many years, and haven't really given them much thought. But I recently got egg on my face by assuming that delegates included a 'this' reference in the signature when referencing a class method. The below example illustrates the gap in my understanding.

public class SomeClass
{
    public SomeClass(int someProperty)
    {
        SomeProperty = someProperty;
    }

    public int SomeProperty
    { 
        get; 
        set; 
    }

    // Throw in a Member field into the mix
    public int ClassAdd(int x, int y)
    {
        return x + y + SomeProperty;
    }
}

public static class SomeStaticClass
{
    public static int StaticAdd(int x, int y)
    {
        return x + y;
    }
}

Why is it that I can add both static and instance subscribers?

    delegate int addDelegate(int x, int y);

    class TestClass
    {
        delegate int addDelegate(int x, int y);

        private void useDelegates()
        {
            addDelegate algorithm;
            algorithm = SomeStaticClass.StaticAdd;
            algorithm += new SomeClass(3).ClassAdd;

            int answer = algorithm(5, 10);
        }
    }

What is actually going on ;)

Thanks!

+3  A: 

If you create a delegate referring to an instance method, it will capture this (or the relevant reference) in the field backing the Target property of the delegate. If you create a delegate referring to a static method, the Target will be null. Logically there's no need to have an instance if you're using a static method.

As one added complications, you can capture extension methods as if they were instance methods on the extended type:

static class Extensions
{
    public static void Foo(this string x)
    {
        Console.WriteLine("Calling Foo on " + x);
    }
}

class Test
{
    static void Main()
    {
        Action action = "text".Foo;
        Console.WriteLine(action.Target); // Prints "text"
    }
}

As for why you can do all of this: because it's useful, and there's no reason not to allow you to do it :)

Jon Skeet
Yup, delegate has Target and Method properties. Silly me.http://msdn.microsoft.com/en-us/library/4k6c0ad6.aspx
nonnb
as shame that this is the only curry'ing that the language has build in would have been grate if they had build extension method delegates on a curry'ing syntax and/or machinery :)
Rune FS
+1  A: 

There are no static functions in C#, they are actually static methods (so there are static and instance methods). Every delegate basically is pointer to method and this pointer on which the method will be executed, it is Target property of delegate. In case of static method it will be null. Since delegate carry reference to objects it can cause memory leaks if you forget to unsubscribe.

Andrey
+1  A: 

The beauty of delegates is that they just work, for both static and instance methods. If you assign a static method to a delegate, the static method is simply used as-is, since it doesn't need any non-static context to work. For instance methods, a reference to the instance is stored along the method pointer, so that the necessary context (the this reference) is available when the method is called. This means that when you assign an instance method to a delegate, you must also provide an instance - either by specifying it explicitly, or by assigning to the delegate from inside an instance context.

Most of the time, this 'just works', and you don't need to think about anything. There is one caveat though: If you assign an instance method to a delegate, you create another reference to the instance, and as long as the method remains assigned to the delegate (or subscribed to an event), there will also be a reference to the instance, so the GC will never collect it. This is why you should always unsubscribe from all events when cleaning up after yourself.

tdammers
Thanks for the point on memory leaks Andrey + tdammers
nonnb