user950851
user950851

Reputation: 77

.NET Delegate passed as parameter issue

Confused by C# delegate passing as parameter:

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        Action holder = delegate{};
        //a.Attach1(holder); //nothing printed
        a.Attach2(ref holder);//print as expected

        holder();
    }
}

public class A
{
    private void P1()
    {
        Console.WriteLine("Inaccessible");
    }
    public void P2()
    {
        Console.WriteLine("Accessible");
    }
    public void Attach1(Action holder)
    {
        holder += P1;
        holder += P2;
    }
    public void Attach2(ref Action holder)
    {
        holder += P1;
        holder += P2;
    }
}

delegate is reference type, why does it still need to be passed with ref in font to work correctly as in Attach2, something like value type?

From C++ experience, delegate is just a function pointer, Attach1(Action holder) is something like Attach1(Action* holder), the origial holder is passed as 'value', thus not assigned, while in the second case, Attach2(ref Action holder) is something like Attach1(Action** holder), the pointer is actually passed, thus can be manipulated correctly. But why in .NET there is no indication or hint???

Upvotes: 3

Views: 223

Answers (4)

doctorlove
doctorlove

Reputation: 19232

I presume you are just experimenting with this. You would normally send the function in that you wanted to be added to a member delegate, and then the member would be the new object return by +=

public class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        a.Attach();
        a.doSomething();
    }
}

public class A
{
    public delegate void handler();
    public handler doSomething;
    private void P1()
    {
        Console.WriteLine("Inaccessible");
    }
    public void P2()
    {
        Console.WriteLine("Accessible");
    }
    public void Attach()
    {
        doSomething += P1;
        doSomething += P2;
    }
}

Upvotes: 0

jekcom
jekcom

Reputation: 2095

As stated on MSDN

Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.

See the second example on that link, it explains the question

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062502

Because a delegate instance is immutable, and += is a new assignment to a new delegate instance; it is basically:

holder = (Action)Delegate.Combine(holder, P1);
holder = (Action)Delegate.Combine(holder, P2);

If you don't pass that as ref, the new value will not be seen outside the method.

Or to put that in simpler terms - consider a string; a string is likewise immutable and += is an assignment. Now consider:

public void Append(string s) {
    s += "[suffix]";
}
public void Append2(ref string s) {
    s += "[suffix]";
}

If we call:

string x = "abc";
Append(x);
Console.WriteLine(x);

we will see abc. If we call

string x = "abc";
Append2(ref x);
Console.WriteLine(x);

we will see abc[suffix] - for the exact same reasons.

Upvotes: 6

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239636

holder += P1;

This line effectively creates a new delegate and assigns it to the holder variable. It doesn't modify the existing delegate.

So:

Action holder = delegate{};
a.Attach2(ref holder);

holder(); //<-- holder is no longer the delegate assigned two lines above

And of course, you need to use ref to make this work, since otherwise the assignment inside Attach2 only affects what is effectively a local variable.

Upvotes: 2

Related Questions