c# - 未为动态泛型解析方法

标签 c# generics dynamic

我有这些类型:

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.Save(Attachment)”的最佳重载方法匹配有一些无效参数

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/

相关文章:

c# - 如何在 c#.Net 中创建透明面板

c# - 使用 avimanager 从图像生成视频会引发错误

C#:如何对动态对象执行空值检查

c# - C# 中的泛型类型

c# - 如何将变量转换为与动态变量相同的类型?

android - 从 Android 中的 APK 文件加载上下文

c# - 如何检测 HTTPWebRequest 中的客户端证书身份验证请求?

c# - 隐式 'this'无法引用Xamarin中的扩展方法

数组中数组的 Swift 通用扩展

swift - 如何在父类(super class)中定义一个函数,该函数在 Swift 中进行子类化时将使用子类的类型?