C#delegate因参数传递而感到困惑:
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;
}
}
委托是引用类型,为什么仍然需要使用ref in font传递才能正常工作,如在Attach2中,类似于值类型?
从C ++经验来看,委托只是一个函数指针,Attach1(Action holder)就像Attach1(Action * holder),原始持有者作为'value'传递,因此没有赋值,而在第二种情况下,Attach2 (ref Action holder)类似于Attach1(Action ** holder),指针实际传递,因此可以正确操作。但是为什么在.NET中没有任何迹象或暗示?
答案 0 :(得分:6)
因为委托实例是不可变的,而+=
是对新委托实例的新分配;它基本上是:
holder = (Action)Delegate.Combine(holder, P1);
holder = (Action)Delegate.Combine(holder, P2);
如果您没有将其作为ref
传递,则不会在方法外看到新值。
或者用简单的术语来说 - 考虑一个string
; string
同样是不可变的,+=
是一项任务。现在考虑:
public void Append(string s) {
s += "[suffix]";
}
public void Append2(ref string s) {
s += "[suffix]";
}
如果我们致电:
string x = "abc";
Append(x);
Console.WriteLine(x);
我们会看到abc
。如果我们打电话
string x = "abc";
Append2(ref x);
Console.WriteLine(x);
我们会看到abc[suffix]
- 的原因完全相同。
答案 1 :(得分:2)
holder += P1;
这一行有效地创建了一个 new 委托,并将其分配给holder
变量。它不会修改现有的委托。
所以:
Action holder = delegate{};
a.Attach2(ref holder);
holder(); //<-- holder is no longer the delegate assigned two lines above
当然,您需要使用ref
来完成这项工作,否则Attach2
内的分配只影响实际上是局部变量。
答案 2 :(得分:0)
正如MSDN
所述不要将通过引用传递的概念与概念相混淆 参考类型。这两个概念不尽相同。方法参数 可以通过ref修改,无论它是值类型还是a 参考类型。传递时没有值类型的装箱 通过引用。
请参阅该链接的第二个示例,它解释了问题
答案 3 :(得分:0)
我认为你只是在尝试这个。您通常会发送函数,因为您希望将其添加到成员委托中,然后该成员将是新对象返回+ =
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;
}
}