c#抽象类泛型属性

时间:2012-01-09 22:29:11

标签: c# entity-framework-4 abstract-class poco

请考虑以下代码:

public abstract class RepositoryBase<T> where T : class
{
    #region Members

    private MyContext dataContext;
    private readonly IDbSet<T> dbset;

    #endregion

    protected RepositoryBase(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get; private set;
    }

    protected MyContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    public virtual void Delete(T entity)
    {
        dbset.Remove(entity);
    }

我想用下面的方法替换Delete方法,因为我更喜欢在我的对象中将Deleted字段设置为true以表示它已被删除,而不是真正删除它。

    public virtual void Delete(T entity)
    {
        entity.Deleted = true;
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }

我正在使用POCO实体,并且所有这些实体都存在Deleted属性。但是,在上面的代码中,实体的类型为T,并且T“不知道”它可以表示的所有对象中都有Deleted属性。解决这个问题最优雅的方法是什么?

顺便说一下,我想在抽象类中以类似的方式访问其他字段(DateCreated,CreatedBy,DateModified和ModifiedBy)。

UPDATE :我尝试了接口和Abstract类解决方案,起初看起来很不错,但在编译时两种情况下我都收到以下错误消息:

  

错误11“MyProject.Domain.Person”类型不能在泛型类型或方法“MyProject.Data.Infrastructure.RepositoryBase”中用作类型参数“T”。没有从“MyProject.Domain.Person”到“MyProject.Domain.AbstractEntity”的隐式引用转换。

以下是错误消息所指的代码:

namespace MyProject.Data
{ 
    public class PersonRepository : RepositoryBase<Person>, IPersonRepository
    {
        public PersonRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }
    }

    public interface IPersonRepository : IRepository<Person>
    {

    }
}

更新2:

我终于得到了SLaks提出的解决方案。我使用了一个接口,并修改了生成所有POCO实体的模板,以便它们都来自以下IEntity接口:

namespace MyProject.Domain
{
    public interface IEntity
    {
        System.DateTime CreatedDate
        {
            get;
            set;
        }

        string CreatedBy
        {
            get;
            set;
        }

        System.DateTime ModifiedDate
        {
            get;
            set;
        }

        string ModifiedBy
        {
            get;
            set;
        }

        bool Deleted
        {
            get;
            set;
        }
    }
}

使用抽象实体类会更复杂,因为抽象类中的所有属性都必须在实体类中重写。

4 个答案:

答案 0 :(得分:5)

将Deleted属性放入接口(比方说,IDeleteable),并使用通用约束约束类:

public interface IDeleteable { Boolean Deleted { get; set; } }

public abstract class RepositoryBase<T> where T : class, IDeleteable
编辑:我认为这是隐含的,但您需要在实体类中实现接口,例如。

public class Person : IDeleteable { ... }

答案 1 :(得分:3)

您应该创建一个包含Deleted和其他属性的界面,并在您的实体类中实现它 然后,您可以约束泛型类型参数以实现接口。

答案 2 :(得分:3)

您可以使用抽象类进行约束

// from
public abstract class RepositoryBase<T> where T : class

// to
public abstract class RepositoryBase<T> where T : AbstractEntity

AbstractEntity 将拥有您需要的所有属性。与接口相比,抽象类将允许您提供一些默认实现。

答案 3 :(得分:1)

其他人提到使用接口或抽象类。这也是我全心全意推荐的。如果由于某些愚蠢的原因,这是不可能的,你也可以使用反射:

entity.Deleted = true;

将替换为:

var type = typeof(T);
var property = type.GetProperty("Deleted");
property.SetValue(entity, true, null);