c# – 方法未被动态泛型类型解析

前端之家收集整理的这篇文章主要介绍了c# – 方法未被动态泛型类型解析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有这些类型:
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< Attachment> .Save(附件)’有一些无效的参数

var obj = new Attachment() { /* set properties */ };
obj.Save();

我已经验证了在DomainObject.Save()“这”绝对是Attachment,所以错误并没有真正的意义.任何人都可以清楚,为什么方法不能解决

一些更多的信息 – 如果将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.

这里,组成的表达式具有编译时类型DomainObject< int> (简化:源代码是一种通用类型,因此我们应该如何“查看”这个编译时类型,但希望我的意思是被理解),因为这不是动态类型或type-parameter,其类型作为其编译时类型.

所以绑定器查找一个方法Save一个类型为DomainObject< int>的单个参数(或者在编译时传递类型为DomainObject< int>的对象是合法的).

看起来有点像这样在编译时发生了约束:

// 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>所关心的唯一候选方法 – 是附件保存(附件),对于此方法,从参数类型(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'

而这是使用动态版本延迟到运行时的错误.反射没有相同的问题,因为它不会在编译时尝试提取方法调用相关的“局部”信息,而不像动态版本.

幸运的是,修复很简单,推迟了组件表达式的评估:

dao.Save((dynamic)this);

这使我们进入选项1(编译时类型动态).构成表达式的类型推迟到运行时,这有助于我们绑定到正确的方法.那么代码的静态等价物就像:

// 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#相关文章