动态操作解析(dynamic operator resolution)

2019-08-05 19:26发布

我有一个由铸造操作数的一个电话运营商的通用方法dynamic 。 有两种不同的呼叫:

//array is T[][]
//T is MyClass
array[row][column] != default(T) as dynamic

这工作,并调用static bool operator !=(MyClass a, MyClass b)即使双方都null )。

让我吃惊的是以下行的行为:

//array, a and b are T[][]
//T is MyClass
array[row][column] += a[line][i] * (b[i][column] as dynamic);

这就要求
public static MyClass operator *(MyClass a, object b)
public static MyClass operator +(MyClass a, object b)

并不是
public static MyClass operator *(MyClass a, MyClass b)
public static MyClass operator +(MyClass a, MyClass b)

卸下(MyClass, object)运营商的原因

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException wurde nicht behandelt.
  HResult=-2146233088
  Message=Der *-Operator kann nicht auf Operanden vom Typ "[...].MyClass" und "object" angewendet werden.
  Source=Anonymously Hosted DynamicMethods Assembly
  StackTrace:
       bei CallSite.Target(Closure , CallSite , MyClass , Object )
       bei System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
       bei [...].MatrixMultiply[T](T[][] a, T[][] b) in 
       [...]
  InnerException: 

(椭圆矿)。

为什么?
我可以调用没有明确地调用合适的操作T Operators.Add<T>(T a, T b)方法,而不是运营商?

更新

public static T TestMethod<T>(this T a, T b)
    {
        return (T)(a * (b as dynamic));
    }

这种方法在一个单独的组件调用(或试图调用) operator *(T, object) ,如果相同的方法是在它正确地调用主组件operator *(T, T)

我作为类型参数使用类是internal ,当我将其更改为问题消失public ,所以它似乎取决于对方法的类的知名度。

operator *(T, object)被成功调用,即使这个类是不可见的。

Answer 1:

这听起来像你在一个有趣的设计决策跌跌撞撞 - 不是一个错误,这是故意的 - 动态功能。 我一直在博客这一块有一段时间了。

首先,让我们退一步。 动态特征的基本想法是,包含有动态类型的操作数的表达式是否它的类型分析推迟到运行时。 在运行时,类型分析是通过转起来时,编译器的新版本,并重新做了分析,此时治疗的动态表情,就好像是它的实际运行时类型的表达式做新鲜。

所以,如果你有在编译时有对象的左手编译时类型,以及动态右手编译时类型的另外的表达,并在运行时的动态表现,其实是一个字符串,那么分析用左手侧为对象,右边是字符串重新做。 请注意,左侧的运行时类型不考虑 。 它的编译时类型为对象,而不是动态的。 动态类型的表达式,只有有自己的运行时类型是在运行时分析中使用的属性。

只是为了确保清楚:如果您有:

void M(Giraffe g, Apple a) {...}
void M(Animal a, Fruit f) { ... }
...
Animal x = new Giraffe();
dynamic y = new Apple();
M(x, y);

然后在运行时,所述第二倍率被调用。 事实上,在运行时,x是长颈鹿被忽略 ,因为它不是动态的。 这是动物在编译时,所以在运行时它继续被分析为Animal类型的表达式。 也就是说,就像您说的分析完成:

M(x, (Apple)y);

而且显然选择第二个过载。

我希望这是明确的。

现在我们来对这个问题的肉。 当运行时类型不会有访问,会发生什么? 让我们实际工作的一个示例:

public class Fruit {}
public class Apple : Fruit 
{
  public void M(Animal a) {}
  private class MagicApple : Apple 
  {
    public void M(Giraffe g) {}
  }
  public static Apple MakeMagicApple() { return new MagicApple(); }
}
...
dynamic d1 = Apple.MakeMagicApple();
dynamic d2 = new Giraffe();
d1.M(d2);

OK,会发生什么? 我们有两个动力表现,所以根据我先前说的,在运行时,我们又做了分析,但假装你说

((Apple.MagicApple)d1).M((Giraffe)d2));

所以你会认为重载决议会选择的方法Apple.MagicApple.M恰好匹配。 但事实并非如此! 我们不能假装上面的代码就是你说的,因为该代码访问以外的访问域私人嵌套类型! 该代码将不能完全编译。 但同样很明显,我们不能让这种代码失败,因为这是一个常见的场景。

所以,我一定要订正我先前的发言。 什么是运行时分析引擎实际上做的是假装你插入蒙上,你可以在法律上已插入 。 在这种情况下,实现了用户可能已插入:

((Apple)d1).M((Giraffe)d2));

和重载决议会选择Apple.M

此外:假扮铸件总是以类类型。 这可能是有一个接口类型,或者可能已经插入一个类型参数类型转换会导致重载解析成功,但通过使用你曾表示希望使用的运行时类型和运行时类型“动态”一个目的是从未接口或类型参数类型。

这听起来像你是在同一条船上。 如果动态表达式的运行时类型不会已经在调用点进入,然后它被视为是其最接近的接入基站类型,运行时分析的目的。 在你的情况,最近访问的基本类型可能是对象。

这就是全部清楚了吗?



文章来源: dynamic operator resolution