gpt4 book ai didi

c# - C# 动态中不可预测的行为

转载 作者:行者123 更新时间:2023-12-02 15:20:22 24 4
gpt4 key购买 nike

我在学习 C# 动态过程中发现了一个错误(功能?)。谁能解释一下,为什么我有异常(exception)?

static class Program
{
public static void Main(string[] args)
{
dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));

var executer = someObj.Execute;
executer(); // shows "wtf"
someObj.Execute(); // throws RuntimeBinderException

Console.ReadKey();
}

static dynamic ConstructSomeObj(dynamic param)
=> new { Execute = param };
}

注意:exectuer 和 someObj 的 typeof 都是动态的

最佳答案

让我们看一下下面的代码:

using System;
using System.Collections.Generic;


public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");

// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();

// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();

}
}

dynamic 使用反射来访问对象方法和字段,并且由于它无法知道确切的类型,因此它必须依赖于其操作的对象中存在的类型信息。

当匿名类型中的字段x正确键入为委托(delegate)调用时,foo.x()起作用,因为dynamic可以看到该字段值是委托(delegate)。

当您使用时

static dynamic ConstructSomeObj(dynamic param) 
{ return new { x = param }; }

为了创建匿名类,您创建了具有object类型的字段x的类(动态是object在幕后)。当您调用 obj.x 时,dynamic 会看到该字段类型是一个对象,并且它不会检查该字段指向的确切类型。由于对象没有像委托(delegate)那样的 Invoke() 方法,因此它会抛出异常。如果将方法参数类型更改为 Action 它将起作用。

我认为检查字段类型而不是字段包含的值类型的决定是为了提供更好的性能。换句话说,当您检查由 dynamic 生成的字段类型 CallSite 类时,可以缓存并稍后重用。

引用文献: https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs

https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpInvokeMemberBinder.cs

编辑:在单声道上检查了这一点,有人可以在 VS 上验证

关于c# - C# 动态中不可预测的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38114762/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com