我有这些类型:
public class GenericDao<T>
{
public T Save(T t)
{
return t;
}
}
public abstract class DomainObject {
// Some properties
protected abstract dynamic Dao { get; }
public virtual void Save() {
var dao = Dao;
dao.Save(this);
}
}
public class Attachment : DomainObject
{
protected dynamic Dao { get { return new GenericDao<Attachment>(); } }
}
然后,当我运行这段代码时,它失败并出现 RuntimeBinderException:“GenericDAO
var obj = new Attachment() { /* set properties */ };
obj.Save();
我已经验证在 DomainObject.Save() 中“this”肯定是附件,所以这个错误没有意义。任何人都可以阐明为什么该方法无法解析吗?
更多信息 - 如果我将 DomainObject.Save() 的内容更改为使用反射,它会成功:
public virtual void Save() {
var dao = Dao;
var type = dao.GetType();
var save = ((Type)type).GetMethod("Save");
save.Invoke(dao, new []{this});
}
最佳答案
问题是动态方法调用的某些方面是在编译时解决的。这是设计使然。来自语言规范(强调我的):
7.2.3 Types of constituent expressions
When an operation is statically bound, the type of a constituent expression (e.g. a receiver, and argument, an index or an operand) is always considered to be the compile-time type of that expression. When an operation is dynamically bound, the type of a constituent expression is determined in different ways depending on the compile-time type of the constituent expression:
• A constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
• A constituent expression whose compile-time type is a type parameter is considered to have the type which the type parameter is bound to at runtime
• Otherwise the constituent expression is considered to have its compile-time type.
在这里,组成表达式 this
有一个编译时类型 DomainObject<int>
(简化:源代码是通用类型,因此我们应该如何“查看” this
的编译时类型变得复杂,但希望我的意思能够理解),并且由于这不是动态类型或类型参数,其类型被视为其编译时类型。
所以 Binder 寻找一个方法Save
采用 DomainObject<int>
类型的单个参数(或者在编译时向其传递 DomainObject<int>
类型的对象是合法的)。
如果绑定(bind)发生在编译时,它看起来有点是这样的:
// Extra casts added to highlight the error at the correct location.
// (This isn't *exactly* what happens.)
DomainObject<int> o = (DomainObject<int>) (object)this;
GenericDao<Attachment> dao = (GenericDao<Attachment>)Dao;
// Compile-time error here.
// A cast is attempted from DomainObject<int> -> Attachment.
dao.Save(o);
但这行不通,因为唯一关注的候选方法是 GenericDao<Attachment>
是Attachment Save(Attachment)
, 对于此方法,不存在从参数类型 ( DomainObject<int>
) 到参数类型 ( Attachment
) 的隐式转换。
所以我们得到编译时错误:
The best overloaded method match for 'GenericDao<Attachment>.Save(Attachment)' has some invalid arguments
Argument 1: cannot convert from 'DomainObject<int>' to 'Attachment'
this 是延迟到运行时使用 dynamic
的错误版本。与 dynamic
不同,反射没有相同的问题,因为它不会尝试在编译时提取有关方法调用的“部分”信息。版本。
幸运的是,修复很简单,推迟对构成表达式类型的评估:
dao.Save((dynamic)this);
这使我们进入选项 1(编译时类型 dynamic
)。 constituent-expression 的类型被推迟到运行时,这有助于我们绑定(bind)到正确的方法。然后代码的静态绑定(bind)等价物是这样的:
// Extra casts added to get this to compile from a generic type
Attachment o = (Attachment)(object)this;
GenericDao<Attachment> dao = (GenericDao<Attachment>)Dao;
// No problem, the Save method on GenericDao<Attachment>
// takes a single parameter of type Attachment.
dao.Save(o);
应该可以正常工作。
关于c# - 未为动态泛型解析方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4674564/