通过外部静态扩展调用动态转换为类型保持动态

Cast dynamic to type through external static extension call stays dynamic

我有一个奇怪的行为。

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

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);

我无法使用铸造扩展访问任何形式 properties/methods:

ToType<Form>(AnyLabel.Tag.ToType<dynamic>().Item2).Show();

我的问题是,为什么第一个 var 不是来自 type form 并且拒绝我执行最后的代码部分?

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

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


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

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.