为什么 dynamic .ToString() (string.Format(), Convert.ToString()) returns 是动态的而不是字符串?
Why dynamic .ToString() (string.Format(), Convert.ToString()) returns dynamic and not string?
此问题仅用于教育目的。我有这段代码在我想将行写入文件的行的编译时失败。 (File.WriteAllLines(@"C:\temp\processed.txt",contents);
)
错误信息:
Argument 2: cannot convert from
'System.Collections.Generic.List<dynamic>'
to
'string[]' C:\hg\PricingEngine\Source\App\Support\PricingEngine.Migrator\Program.cs 49 57 PricingEngine.Migrator
Error 6 The best overloaded method match for
'System.IO.File.WriteAllLines(string, string[])' has some invalid
arguments C:\hg\PricingEngine\Source\App\Support\PricingEngine.Migrator\Program.cs 49 13 PricingEngine.Migrator
如果我注释掉最后一行并用断点检查所有行都是字符串,一切正常。
代码:
public static void Main()
{
var t = new List<dynamic>
{
new {name = "Mexico", count = 19659},
new {name = "Canada", count = 13855},
};
var stringed = t.Select(o => string.Format("{0} {1}", o.name, o.count)).Select(o => Convert.ToString(o)).ToList();
File.WriteAllLines(@"C:\temp\processed.txt", stringed);
}
这是怎么回事 为什么动态 ToString()、string.Format() 和 Convert.ToString() 是动态的?我在这里遗漏了什么明显的东西吗?
由于动态的工作原理,编译器不知道 t.name
的类型,因此无法为 File.WriteAllLines
方法找到正确的重载。一种解决方案可能是将 t.name
显式转换为 string
,但在您的情况下,您可以对数组使用隐式类型并完全停止使用动态:
var t = new[]
{
new {name = "Mexico", count = 19659},
new {name = "Canada", count = 13855},
new {name = "U.K.", count = 3286},
new {name = "France", count = 2231},
new {name = "Italy", count = 2201},
new {name = "Germany", count = 1688},
new {name = "Jamaica ", count = 1688},
new {name = "Bahamas ", count = 1538},
new {name = "Japan", count = 1538},
new {name = "People's Republic of China", count = 1327},
new {name = "Spain", count = 995},
new {name = "Netherlands", count = 904},
new {name = "Hong Kong", count = 904},
new {name = "India", count = 904},
new {name = "Ireland", count = 844},
new {name = "Republic of China (Taiwan)", count = 693},
new {name = "Switzerland ", count = 633},
new {name = "Republic of Korea", count = 633},
new {name = "Australia", count = 603},
new {name = "Greece", count = 482},
};
在我看来你的问题真的可以归结为:
dynamic d = "x";
var v = Convert.ToString(d);
... v
的编译时类型是 dynamic
,如在 Visual Studio 中将鼠标悬停在它上面所示,您会期望它是 string
.不需要列表或文件。
那么,这是为什么呢?基本上,C# 有一个简单的规则:几乎所有使用动态值的操作的结果都是 dynamic
。这意味着在执行时是否可以使用编译时不知道的额外重载并不重要,例如。
我知道涉及动态值的操作结果不是动态的唯一操作是:
is
运算符,例如var b = d is Foo; // Type of b is bool
- 演员表,例如
var x = (string) d; // Type of x is string
as
运算符,例如var y = d as string; // Type of y is string
- 构造函数调用,例如
var z = new Bar(d); // Type of z is Bar
对于方法调用的简单情况,C# 5 规范的第 7.6.5 节明确指出 Convert.ToString(d)
的类型为 dynamic
:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
- The primary-expression has compile-time type dynamic.
- At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
In this case the compiler classifies the invocation-expression as a value of type dynamic
.
(作为旁注,“并且 主要表达式 没有委托类型”部分似乎没有在任何地方得到解决,或者被编译器。如果你有一个 Func<string, string> func = ...; var result = func(d);
,result
的类型似乎仍然是 dynamic
而不是 string
。我会调查一下...)
此问题仅用于教育目的。我有这段代码在我想将行写入文件的行的编译时失败。 (File.WriteAllLines(@"C:\temp\processed.txt",contents);
)
错误信息:
Argument 2: cannot convert from
'System.Collections.Generic.List<dynamic>'
to 'string[]' C:\hg\PricingEngine\Source\App\Support\PricingEngine.Migrator\Program.cs 49 57 PricingEngine.MigratorError 6 The best overloaded method match for 'System.IO.File.WriteAllLines(string, string[])' has some invalid arguments C:\hg\PricingEngine\Source\App\Support\PricingEngine.Migrator\Program.cs 49 13 PricingEngine.Migrator
如果我注释掉最后一行并用断点检查所有行都是字符串,一切正常。
代码:
public static void Main()
{
var t = new List<dynamic>
{
new {name = "Mexico", count = 19659},
new {name = "Canada", count = 13855},
};
var stringed = t.Select(o => string.Format("{0} {1}", o.name, o.count)).Select(o => Convert.ToString(o)).ToList();
File.WriteAllLines(@"C:\temp\processed.txt", stringed);
}
这是怎么回事 为什么动态 ToString()、string.Format() 和 Convert.ToString() 是动态的?我在这里遗漏了什么明显的东西吗?
由于动态的工作原理,编译器不知道 t.name
的类型,因此无法为 File.WriteAllLines
方法找到正确的重载。一种解决方案可能是将 t.name
显式转换为 string
,但在您的情况下,您可以对数组使用隐式类型并完全停止使用动态:
var t = new[]
{
new {name = "Mexico", count = 19659},
new {name = "Canada", count = 13855},
new {name = "U.K.", count = 3286},
new {name = "France", count = 2231},
new {name = "Italy", count = 2201},
new {name = "Germany", count = 1688},
new {name = "Jamaica ", count = 1688},
new {name = "Bahamas ", count = 1538},
new {name = "Japan", count = 1538},
new {name = "People's Republic of China", count = 1327},
new {name = "Spain", count = 995},
new {name = "Netherlands", count = 904},
new {name = "Hong Kong", count = 904},
new {name = "India", count = 904},
new {name = "Ireland", count = 844},
new {name = "Republic of China (Taiwan)", count = 693},
new {name = "Switzerland ", count = 633},
new {name = "Republic of Korea", count = 633},
new {name = "Australia", count = 603},
new {name = "Greece", count = 482},
};
在我看来你的问题真的可以归结为:
dynamic d = "x";
var v = Convert.ToString(d);
... v
的编译时类型是 dynamic
,如在 Visual Studio 中将鼠标悬停在它上面所示,您会期望它是 string
.不需要列表或文件。
那么,这是为什么呢?基本上,C# 有一个简单的规则:几乎所有使用动态值的操作的结果都是 dynamic
。这意味着在执行时是否可以使用编译时不知道的额外重载并不重要,例如。
我知道涉及动态值的操作结果不是动态的唯一操作是:
is
运算符,例如var b = d is Foo; // Type of b is bool
- 演员表,例如
var x = (string) d; // Type of x is string
as
运算符,例如var y = d as string; // Type of y is string
- 构造函数调用,例如
var z = new Bar(d); // Type of z is Bar
对于方法调用的简单情况,C# 5 规范的第 7.6.5 节明确指出 Convert.ToString(d)
的类型为 dynamic
:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
- The primary-expression has compile-time type dynamic.
- At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
In this case the compiler classifies the invocation-expression as a value of type
dynamic
.
(作为旁注,“并且 主要表达式 没有委托类型”部分似乎没有在任何地方得到解决,或者被编译器。如果你有一个 Func<string, string> func = ...; var result = func(d);
,result
的类型似乎仍然是 dynamic
而不是 string
。我会调查一下...)