鉴于这个简短的示例程序:
static void Main(string[] args)
{
Console.WriteLine(Test("hello world"));
}
private static int Test(dynamic value)
{
var chars = Chars(value.ToString());
return chars.Count();
}
private static IEnumerable<char> Chars(string str)
{
return str.Distinct();
}
运行时,会产生类似于:
的异常 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''object' does not contain a definition for 'Count''
含义编译器选择dynamic
作为chars
变量的首选类型。
考虑到IEnumerable<char>
方法不返回动态,是否有任何理由不选择Chars
作为具体类型?只需手动将类型更改为IEnumerable<char>
即可解决问题,但我想知道为什么dynamic
在这种情况下是默认值?
修改
我可能使用了比必要更复杂的例子。似乎这里提出的问题是:
Anomaly when using 'var' and 'dynamic'
提供更简洁的示例以及一些有关其工作方式的见解。
https://blogs.msdn.microsoft.com/ericlippert/2012/11/05/dynamic-contagion-part-one/
描述编译器如何处理动态。
答案 0 :(得分:5)
使用dynamic
,所有方法调用都在运行时解析。因此,当您调用Chars()
,Count()
甚至ToString()
时,它拒绝猜测编译时实际调用的方法。它可能是任何东西,返回任何东西。这通常被称为“动态传染”。
对于所有编译器都知道,somtimes value.ToString()
将返回MyRandomPOCOClass
,并且在运行时它将能够挖掘一些像Tuple<int,String> Chars(MyRandomPOCOClass x)
这样的重载。也许下次value.ToString()
会返回int
。所有赌注都已关闭。 dynamic
将C#变成脚本语言。
以下是动态运行时重载行为(here's a fiddle)的示例:
public static void Main()
{
dynamic x = "foo";
Test(x);
x = 34;
Test(x);
}
public static void Test(string s)
{
Console.WriteLine("String " + s);
}
public static void Test(int n)
{
Console.WriteLine("Int " + n);
}
输出:
String foo
Int 34
答案 1 :(得分:2)
使用dynamic value
,编译器如何知道value.ToString()
返回什么?
它与我们熟悉的C#方法同名,但它有所不同。
答案 2 :(得分:0)
因为传递给Test()的参数是动态的,并且该参数被传递给Chars()。对于任何涉及动态类型的语句,动态本质上都会将类型检查推迟到运行时,并且就任何涉及动态变量的语句只能产生动态变量而言,就是病毒式的#34;
答案 3 :(得分:0)
使用str.Distinct()时,它返回一个类型的对象
IEnumerable<char>
下的字符变量System.Linq.Enumerable DistinctIterator的char类型。 这本身没有Count方法。它是一个迭代器,内部逐个返回值。 将其投放到IEnumerable<char>
以获取计数。 你可以循环IEnumerable并打印值(对于下面的循环工作正常,因为它是一个迭代器)但是set的底层返回值没有Count方法,除非迭代器类型的变量被强制转换为IEnumerable<char>
。 否则,您可以使用str.Distinct()。ToList(),这将在没有强制转换的情况下正常工作。
static void Main(string[] args)
{
Console.WriteLine(Test("hello world"));
}
private static int Test(dynamic value)
{
var chars = Chars(value.ToString());
//foreach (var c in chars)
// Console.WriteLine(c);
return ((IEnumerable<char>)chars).Count();
}
private static IEnumerable<char> Chars(string str)
{
return str.Distinct();
}