gpt4 book ai didi

c# - 为什么在尝试使用动态参数调用扩展方法时出现错误 CS1973

转载 作者:行者123 更新时间:2023-11-30 14:46:39 26 4
gpt4 key购买 nike

考虑以下代码:

internal static class Program
{
public static string ExtensionMethod(this string format, dynamic args)
{
return format + args.ToString();
}

private static void Main()
{
string test = "hello ";
dynamic d = new { World = "world" };

// Error CS1973 'string' has no applicable method named 'ExtensionMethod'
// but appears to have an extension method by that name.
// Extension methods cannot be dynamically dispatched.
// Consider casting the dynamic arguments or calling
// the extension method without the extension method syntax.
var result = test.ExtensionMethod(d);

// this syntax works fine
var result2 = Program.ExtensionMethod(test, d);

// for whatever reason, this works, too!
var result3 = test.ExtensionMethod((object)d);

// even this works...
var result4 = test.ExtensionMethod(new { World = "world" });

Console.WriteLine(result);
Console.ReadLine();
}
}

我不明白这背后的逻辑。我明白,扩展方法的 first 参数不能是动态的。我什至会理解,如果我传递了一些 另一个动态,调度将无法工作。但显然是这样。它可以将其他类型映射到动态。但是,当我传递该方法所需的确切类型 时,调度不起作用?它不能将 dynamic 映射到 dynamic?这对我来说没有意义。

我可以阅读并理解该错误,并且我显然知道解决方法,但是有人可以启发我为什么存在此错误吗?我看不到的更深层次的问题是什么?


有几个现有的问题可以解释为什么第一个参数 (string) 在这种情况下不能是动态的 - How to call an extension method of a dynamic type?显示将分机调用转换为常规调用的解决方法。确实它适用于我的情况。

也有很多“什么是 CS1973”的问题 (https://stackoverflow.com/search?q=CS1973),但同样大部分都是处理第一个 (this Xxxx) 参数是 dynamic(这听起来很公平)或者只是表现出相同的行为而不解释为什么喜欢 'System.Web.Mvc.HtmlHelper' has no applicable method named 'Partial' (在强类型对象上调用已知扩展,但将 dynamic 作为第二个参数传递)。

但这并不能解释为什么在编译时可以确定单个扩展方法仍然不能使用,这就是这个问题的原因。

最佳答案

因为扩展方法在编译时 绑定(bind)。它们本质上是由编译器转换为静态方法调用,意思是

var result = test.ExtensionMethod(d);

由编译器转换为

var result = Program.ExtensionMethod(test, d);

任何参数是动态时,所有绑定(bind)将延迟到运行时。运行时绑定(bind)器当前不支持编译器知道的扩展方法的绑定(bind),并会生成错误。

And I even would understand if the dispatch would not work if I passed in something but another dynamic.

请记住 dynamic(如 var)不是类型。它只是意味着“我在编译时不知道这是什么类型 - 我会让动态运行时查看实际类型,然后确定如何处理它。

所以当你说:

dynamic d = new { World = "world" };

d 不是“dynamic”。在运行时,d 的值将是一个匿名类型。

可以动态绑定(bind)器支持扩展方法吗?可能,但到目前为止*,附加值还不值得设计、实现、测试、发布和支持此类功能的成本(相对于其他可以添加的东西)。如果您觉得这将是对该框架的一个有值(value)的补充,请随时在 http://connect.microsoft.com/ 提交建议。 .

我还要指出,在您的(尽管是人为的)场景中不需要使用 dynamic 。如果您使用 object 而不是 dynamic (并将扩展方法移至静态类),您将获得完全相同的行为(具有扩展方法支持):

public static string ExtensionMethod(this string format, object args)
{
return format + args.ToString();
}
private static void Main()
{
string test = "hello ";
object d = new { World = "world" };

// Error CS1973 'string' has no applicable method named 'ExtensionMethod'
// but appears to have an extension method by that name.
// Extension methods cannot be dynamically dispatched.
// Consider casting the dynamic arguments or calling
// the extension method without the extension method syntax.
var result = test.ExtensionMethod(d);

// this syntax works fine
var result2 = Program.ExtensionMethod(test, d);

// for whatever reason, this works, too!
var result3 = test.ExtensionMethod((object)d);

// even this works...
var result4 = test.ExtensionMethod(new { World = "world" });

Console.WriteLine(result);
Console.ReadLine();
}

* 至少在 2011 年,在这种情况下找到调用方法的问题被认为太难了 - 请参阅 Eric Lippert 的回答 - https://stackoverflow.com/a/5313149/477420 : "...这意味着为了正确解析动态扩展方法调用,DLR 必须在运行时以某种方式知道源代码中的所有命名空间嵌套和使用指令。我们没有将所有信息编码到调用站点的方便机制......”

关于c# - 为什么在尝试使用动态参数调用扩展方法时出现错误 CS1973,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48324768/

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