c# dynamic用法 - 为什么调用ISet <dynamic> .Contains()编译,但在运行时抛出异常?




3 Answers

到目前为止,您收到的答案并未解释您所看到的行为。 DLR应该找到方法ICollection<object>.Contains(object)并使用盒装整数作为参数调用它,即使变量的静态类型是ISet<dynamic>而不是ICollection<dynamic> (因为前者派生)从后者)。

因此,我认为这是一个错误, 我已将其报告给Microsoft Connect。 如果事实证明这种行为在某种程度上是可取的,那么他们会在那里发表评论。

dynamic关键字 dynamic作用

请帮我解释一下这个行为:

dynamic d = 1;
ISet<dynamic> s = new HashSet<dynamic>();
s.Contains(d);

代码编译没有错误/警告,但在最后一行我得到以下异常:

Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains'
   at CallSite.Target(Closure , CallSite , ISet`1 , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
   at FormulaToSimulation.Program.Main(String[] args) in 

据我所知,这与动态重载分辨率有关,但奇怪的是

(1)如果s的类型是HashSet<dynamic> ,则不会发生异常。

(2)如果我使用非泛型接口和接受动态参数的方法,则不会发生异常。

因此,看起来这个问题特别与通用接口有关,但我无法找出导致问题的确切原因。

它是编译器/类型系统中的错误还是合法行为?




Contains方法在ICollection<T>上定义,而不是在ISet<T> 。 CLR不允许从派生接口调用接口基本方法。 您通常不会看到静态解析,因为C#编译器足够聪明,可以发出对ICollection<T>.Contains ,而不是不存在的ISet<T>.Contains

编辑: DLR模仿CLR行为,这就是您获得异常的原因。 您的动态调用是在ISet<T> ,而不是HashSet<T> ,DLR将模仿CLR:对于接口,只搜索接口方法,而不是基本接口(与存在此行为的类相反)。

有关深入解释,请参阅我之前对类似问题的回复:

使用动态类型作为方法参数时的奇怪行为




ISet接口没有'Contains'方法,但是HashSet呢?

编辑我想说的是当给定HashSet concreate类型时绑定器解析'Contains',但是在界面中找不到继承的'Contains'方法...




Related