Reputation: 77
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
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
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
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
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