用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.为什么?

推荐答案

原因如下:

声明委托的方式直接指向静态int实例的ToString方法.它在创造时被捕获.

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

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

之后,将I更改为不同的值,基本上为其分配一个新实例.这并不会神奇地改变代理中捕获的实例,为什么要这样做呢?

要获得预期的结果,需要将代理更改为:

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

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

在本例中,要执行的方法是在中声明委托的类中创建的匿名方法.实例为空,因为它是一个静态方法.

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

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

正如你所看到的,这是一个正常的方法,可以做到something.在我们的例子中,它返回对I的当前实例调用ToString的结果.

.net相关问答推荐

尽管有`disable`注释,但未 suppress Pylint语法错误

DotNet COM初始化问题

EF Core IEntityTypeConfigurations:从数据库提取数据后相关对象为空

.NET Core 中的微服务

ECS服务无法从Cognito获取配置

您可以为 Func 或 Action 类型的函数或子参数指定默认值吗?

System.IO.Directory.Exists 在 LINQ 语句中失败,但在 foreach 循环中没有

根源是什么?

C#6.0 字符串插值本地化

如何使用 C# 中的代码更改网络设置(IP 地址、DNS、WINS、主机名)

每第 N 个字符/数字拆分一个字符串/数字?

我应该默认推荐密封类吗?

为什么递归调用会导致不同堆栈深度的 StackOverflow?

注册 COM 互操作与使程序集 COM 可见

如何在 C# 中直接执行 SQL 查询?

从 List 到数组 T[] 的转换

List 是否保证项目将按照添加的顺序返回?

在 .NET Core 中在 MVC 之外使用 Razor

Microsoft.Bcl.Build NuGet 包有什么作用?

任何人都知道缺少枚举通用约束的好方法吗?