繁体   English   中英

.NET委托作为参数问题传递

[英].NET Delegate passed as parameter issue

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中没有任何迹象或暗示?

因为委托实例是不可变的 ,而+=委托实例的新赋值; 它基本上是:

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] - 出于完全相同的原因

holder += P1;

该行有效地创建了一个委托,并将其分配给holder变量。 它不会修改现有的委托。

所以:

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

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

当然,你需要使用ref来使这个工作,因为否则Attach2的赋值只会影响实际上是局部变量。

正如MSDN上所述

不要将引用传递的概念与引用类型的概念混淆。 这两个概念不尽相同。 无论是值类型还是引用类型,都可以通过ref修改方法参数。 通过引用传递时,没有值类型的装箱。

请参阅该链接的第二个示例,它解释了这个问题

我认为你只是在尝试这个。 您通常会发送函数,因为您希望将其添加到成员委托中,然后该成员将是新对象返回+ =

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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM