通过外部静态扩展调用将动态转换为动态

时间:2017-10-08 15:10:01

标签: c# dynamic casting extension-methods

我有一种奇怪的行为。

我使用以下方法将任何对象强制转换为任何给定的类型。

using System.Dynamic;

...

/// <summary>
/// Casts any object to passed type.
/// </summary>
/// <typeparam name="T">Wished type</typeparam>
/// <param name="obj">The object you want to be casted.</param>
public static T ToType<T>(this object obj) => (T)obj;

例如(对象为动态):

AnyLabel.Tag = new ExpandoObject();
AnyLabel.Tag.ToType<dynamic>().Item2 = new Form(); // works

现在跟随情况(动态到类型化对象):

// var is NOT from type form, why?:
var form = ToType<Form>(AnyLabel.Tag.ToType<dynamic>().Item2);

// the other way works like desired:
var form2 = ((Form)AnyLabel.Tag.ToType<dynamic>().Item2);

我无法使用转换扩展程序àla:

访问任何表单属性/方法
ToType<Form>(AnyLabel.Tag.ToType<dynamic>().Item2).Show();

我的问题是,为什么第一个var不是来自类型形式而且拒绝我执行的最后一个代码部分?

1 个答案:

答案 0 :(得分:1)

方法ToType<T>()可能有重载版本。如果不涉及动态,编译器会在编译时解析正确的重载。如果;然而,涉及动态,绑定在运行时发生,即,在运行时使用参数的运行时类型确定正确的重载。此外,这些重载可能具有不同的返回类型。从现在开始,这个返回类型在编译时是未知的,C#编译器决定选择dynamic作为函数的返回类型。

现在,您可以推断,您没有重载版本,可以安全地假设Form。但是,如果您稍后添加重载会发生什么?这应该突然改变一个没有改变的表达式的返回类型吗?添加重载会导致对在编译时无法检测到的现有代码进行重大更改。

在编译时选择哪种返回类型,如果重载由运行时参数类型确定?

public static T ToType<T>(this object obj) => (T)obj;
public static int ToType<T>(this int i) => i; // Makes no sense, but valid code.
public static dynamic ToType<T>(this dynamic d) => d; // Valid as well.