通用方法是拾取基类的类型

时间:2009-02-18 20:23:02

标签: c# generics inheritance

我有以下类(修剪为仅显示基本结构):

public abstract class BaseModel {
    public bool PersistChanges() {
        // Context is of type "ObjectContext"
        DatabaseHelper.Context.SafelyPersistChanges(this);
    }
}

public static class ObjectContextExtensions {
    public static bool SafelyPersistChanges<T>(this ObjectContext oc, T obj) {
        // Persist the object using a transaction
    }
}

[Persistent("LEADS")]
public class Lead : BaseModel {
    // Extra properties
}

public class LeadsController : Controller {
    public ActionResult Save(Lead lead) {
        lead.PersistChanges()
    }
}

我的潜在客户类派生自 BaseModel ,其中包含使用事务将对象的更改持久保存到数据库的方法。我用扩展方法实现了事务持久化。问题是,通过在 BaseModel 类中将传递给 SafelyPersistChanges ,扩展方法上的泛型T设置为 BaseModel < / strong>即可。但是,由于 BaseModel 未标记为持久对象(它不能),因此ORM框架会抛出异常。

示例:

Lead lead = LeadRepository.FindByNumber(2);
lead.SalesmanNumber = 4;
// Calls "ObjectContextExtensions.SafelyPersistChanges<BaseModel>(BaseModel obj)"
// instead of "ObjectContextExtensions.SafelyPersistChanges<Lead>(Lead obj)"
lead.PersistChanges();

上述块引发了以下异常:

  

如果没有持久属性,则无法为“SalesWeb.Data.BaseModel”类型创建映射。

有什么想法吗?

4 个答案:

答案 0 :(得分:3)

扩展方法在编译时是静态绑定的。在调用SafelyPersistChanges时,它被输入为BaseModel,因此也是您的异常。为了获得你想要的行为,你需要做一个带有大量转换的丑陋if语句或者强制调用派生类。

使PersistChanges成为一种抽象方法。然后使用完全相同的代码在派生类中实现调用。

public class Lead { 
    public override bool PersistChanges() {
        // Context is of type "ObjectContext"
        DatabaseHelper.Context.SafelyPersistChanges(this);
    }
}

现在这将成为Lead

答案 1 :(得分:1)

我会以不同的方式设计它,使“public bool PersistChanges()”调用一个虚方法,在每个子类中重写。

答案 2 :(得分:0)

因此,您需要一个“单一”实现,它根据调用者已知的类型而变化。听起来像是Generics的工作。

public static bool PersistChanges<T>(this T source)
  where T : BaseModel
{
        // Context is of type "ObjectContext"
//static property which holds a Context instance is dangerous.
        DatabaseHelper.Context.SafelyPersistChanges<T>(source);
}

答案 3 :(得分:0)

您可以使用curiously recurring template pattern

解决此问题
// change your code to this

public abstract class BaseModel<TDerived> where TDerived : BaseModel
{
    public bool PersistChanges() {
        // Context is of type "ObjectContext"
        DatabaseHelper.Context.SafelyPersistChanges((TDerived)this);
        //                                            ^
        // note the cast here: -----------------------|
    }
}

public class Lead : BaseModel<Lead> { }

// the rest of your code is unchanged

这样可行,但我可能只是遵循其他建议并使用虚拟方法。