79

在 C# 语言和 .NET 框架中,您能帮我理解代表吗?我试图检查一些代码,发现我收到的结果出乎我的意料。这里是:

class Program
{
    public static int I = 0;

    static Func<string> del = new Func<string>(I.ToString);

    static void Main(string[] args)
    {
        I = 10;
        Console.WriteLine("{0}", del());
    }
}

答案是 0,但不是 10。为什么?

4

5 回答 5

79

原因如下:

您声明委托的方式直接指向ToString静态 int 实例的方法。它是在创建时捕获的。

正如弗林德伯格在下面的评论中指出的那样,每个委托都有一个目标和一个要在目标上执行的方法。

在这种情况下,要执行的方法显然就是ToString方法。有趣的部分是执行该方法的实例:它是I创建时的实例,这意味着委托不是I用来获取要使用的实例,而是存储对实例本身的引用。

稍后您更改I为不同的值,基本上是为其分配一个新实例。这不会神奇地更改您的委托中捕获的实例,为什么要这样做?

要获得您期望的结果,您需要将委托更改为:

static Func<string> del = new Func<string>(() => I.ToString());

像这样,委托指向一个匿名方法,该方法在委托执行ToString时在当前I执行。

在这种情况下,要执行的方法是在声明委托的类中创建的匿名方法。实例为空,因为它是静态方法。

查看编译器为委托的第二个版本生成的代码:

private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0);
private static string cctor>b__0()
{
    return UserQuery.I.ToString();
}

如您所见,这是一种正常的方法。在我们的例子中,它返回调用ToString当前实例的结果I

于 2012-11-28T11:21:09.937 回答
4

您需要传递I给您的函数,以便I.ToString()可以在适当的时间执行(而不是在创建函数时)。

class Program
{
    public static int I = 0;

    static Func<int, string> del = num => num.ToString();

    static void Main(string[] args)
    {
        I = 10;
        Console.WriteLine("{0}", del(I));
    }
}
于 2012-11-28T11:23:51.457 回答
1

这是应该如何完成的:

using System;

namespace ConsoleApplication1
{

    class Program
    {
        public static int I = 0;

        static Func<string> del = new Func<string>(() => {
            return I.ToString();
        });

        static void Main(string[] args)
        {
            I = 10;
            Console.WriteLine("{0}", del());
        }
    }
}
于 2012-11-28T11:24:30.690 回答
0

C#委托启用封装对象和实例以及方法。委托声明定义了派生自 System.Delegate 类的类。委托实例封装了一个调用列表,它是一个或多个方法的列表,每个方法称为可调用实体。

了解更多形式

http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html

于 2015-08-24T10:57:00.833 回答
-2

我的猜测是因为 int 是通过值而不是引用传递的,因此在创建委托时,它是“I”(0)当前值的方法 ToString 的委托。

于 2012-11-28T11:46:51.037 回答