dynamic.ToString() 意外行为

3

我想知道这段代码是怎么工作的:

dynamic dynaString = 2;
string b = dynaString.ToString();

当这个不起作用时:
var list = new List<dynamic>();
var liststring = new List<string>();
liststring = list.Select(x => x.ToString()).ToList();

我知道在Select语句之后可以添加Cast<string>,但这并不能解释这种行为。为什么对动态元素调用ToString()时,与在代码中声明的动态变量上调用时不同于从LINQ列表中获取的动态变量上调用时不同。
我查看了Select方法的签名,它是:

enter image description here

我的猜测是这里的x是一个动态变量,所以它应该像dynaString一样运行,但实际上并不是。Intellisense建议我x.ToString()返回string

enter image description here enter image description here

有没有人在C#中有动态方面的经验,可以向我解释一下?


我也尝试了这段代码:

var list = new List<dynamic>();
var liststring = new List<string>();
foreach (dynamic a in list)
{
    liststring.Add(a.ToString());
}

这段代码如预期一样编译通过,因为在foreach语句中,a被声明为动态类型。


协变性和逆变性。https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/。 - SᴇM
我不确定它是否回答了你的问题,但是 aDynamic.ToString() 的返回类型是动态的,因此 Select<dynamic, dynamic> 被推断出来... 你不会期望将 List<dynamic> 分配给 List<string>。如果你改为指定 Select<dynamic, string>,那应该就可以了。 - steve16351
@steve16351 好有趣...这引发了更多的问题 :) 为什么编译器不选择<dynamic,string>而是选择<dynami,dynamic>呢?我尝试过liststring = list.Select<dynamic,string>(x => x.ToString()).ToList();,它像你说的那样编译通过了 :) - Kamil Budziewski
@steve16351 我同意,不过我猜它可以从期望的结果类型中推断出类型。 - Kamil Budziewski
1
是的,它可能,但我认为那将是基于返回类型的推断,这是不可能的 - steve16351
显示剩余3条评论
1个回答

0
根据动态类型文档
动态类型表示变量的使用及其成员的引用会绕过编译时类型检查。相反,这些操作在运行时解决。
动态类型在大多数情况下都像对象类型一样工作。特别地,任何非空表达式都可以转换为动态类型。动态类型与对象不同之处在于,包含动态类型表达式的操作不会被编译器解析或类型检查。
如果在编译时绕过类型检查和/或解析,则无法从用法推断类型。
如果省略泛型类型参数,则默认返回dynamic类型,即使调用ToString()方法也是如此。原因是任何非空表达式都可以赋值给dynamic。由于dynamic是源,因此它也将是Select(x => x.ToString())方法调用的结果。
另一方面,您可以将dynamic对象分配给string变量,因为您正在调用返回string实例的ToString()方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接