简体   繁体   English

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

[英]Generic method is picking up type of base class

I have the following classes (trimmed to only show the basic structure): 我有以下类(修剪为仅显示基本结构):

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()
    }
}

My Lead class derives from BaseModel , which contains a method to persist the object's changes to the database using a transaction. My Lead类派生自BaseModel ,它包含一个使用事务将对象的更改持久保存到数据库的方法。 I implemented the transactional persist with an extension method. 我用扩展方法实现了事务持久化。 The problem is that by passing this to SafelyPersistChanges in my BaseModel class, the generic T on the extension method is set to BaseModel . 问题是,通过传递 SafelyPersistChangesBaseModel类,在扩展方法一般T设定为BaseModel。 However, since BaseModel isn't marked as a persistent object (which it cannot be), the ORM framework throws an exception. 但是,由于BaseModel未标记为持久对象(它不能),因此ORM框架会引发异常。

Example: 例:

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

The above block raises the following exception: 以上块引发了以下异常:

Cannot create mapping for type 'SalesWeb.Data.BaseModel' without persistent attribute. 如果没有持久属性,则无法为“SalesWeb.Data.BaseModel”类型创建映射。

Any ideas? 有任何想法吗?

Extension Methods are statically bound at compile time. 扩展方法在编译时是静态绑定的。 At the point in which SafelyPersistChanges is called, this is typed as BaseModel and hence your exception. 在调用SafelyPersistChanges时,它被输入为BaseModel,因此也是您的异常。 In order to get the behavior you want, you'll either need to do an ugly if statement with lots of casting or force the call to the derived class. 为了获得你想要的行为,你需要做一个带有大量转换的丑陋if语句或者强制调用派生类。

Make PersistChanges an abstract method. 使PersistChanges成为一种抽象方法。 Then implement the call in the derived classes with exactly the same code. 然后使用完全相同的代码在派生类中实现调用。

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

Now this will properly be Lead 现在这将成为领导者

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

So, you want a "single" implementation, that varies against a type known by the caller. 因此,您需要一个“单一”实现,它根据调用者已知的类型而变化。 Sounds like a job for Generics. 听起来像是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);
}

You could solve this using the 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

That would work, but I'd probably just follow the other suggestions and use a virtual method. 这可行,但我可能只是遵循其他建议并使用虚拟方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM