为什么动态.ToString()(string.Format(),Convert.ToString())返回动态而不是字符串?

时间:2016-08-17 16:04:56

标签: c# dynamic tostring

此问题仅用于教育目的。我有这个代码在编译时失败,我想写行到文件。 (File.WriteAllLines(@"C:\temp\processed.txt",contents);

错误讯息:

  

参数2:无法转换   'System.Collections.Generic.List<dynamic>'来   &#39;串[]&#39; C:\ hg \ PricingEngine \ Source \ App \ Support \ PricingEngine.Migrator \ Program.cs 49 57 PricingEngine.Migrator

     

错误6最佳重载方法匹配   &#39; System.IO.File.WriteAllLines(string,string [])&#39;有一些无效的   参数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()是动态的?我错过了一些明显的东西吗?

2 个答案:

答案 0 :(得分:2)

由于动态如何工作,编译器不知道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},
};

答案 1 :(得分:2)

在我看来,你的问题可以归结为:

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

  

调用表达式是动态绑定的(第7.2.2节),如果至少满足下列条件之一:

     
      
  • primary-expression 具有编译时类型dynamic。
  •   
  • 可选参数列表的至少一个参数具有编译时类型dynamic,而 primary-expression 没有委托类型。
  •   
     

在这种情况下,编译器将 invocation-expression 分类为类型dynamic的值。

(作为旁注,“和 primary-expression 没有委托类型”部分似乎无法在任何地方得到解决,或者被编译器尊重。如果你有一个Func<string, string> func = ...; var result = func(d); result的类型似乎仍然是dynamic而不是string。我会调查一下......)