2012-01-09 83 views
2

考虑下面的代码:C#抽象类一般属性

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

我想与下面的一个替换删除方法,因为我更喜欢简单的设置我的对象已删除字段设置为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)。

更新:我想无论是接口和抽象类的解决方案,这似乎善于第一,但后来我在编译的时候得到了在这两种情况下出现以下错误信息:

错误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; 
     } 
    } 
} 

使用抽象的实体类会比较复杂,因为那么所有的属性抽象类将不得不在实体类中重写。

+0

你问'其中T:类,MyClass'? – Tigran 2012-01-09 22:33:17

+0

@Tigran我尝试过,但是我收到了编译错误消息。看到我上面的更新。 – 2012-01-09 23:54:21

+0

编译器错误意味着Person不从AbstractEntity继承。你忘了重新定义它的基类吗? – phoog 2012-01-10 00:06:16

回答

3

您应该创建Deleted和其他性质的接口,并在你的实体类实现它。
然后,您可以限制泛型类型参数来实现接口。

+0

我想过这个,但是我希望有一个更简单的解决方案,因为我的POCO实体是用T4模板自动生成的。我当然可以修改这个模板,但是T4模板对我来说是很新的,我不知道我能够多快地完成这个修改。 – 2012-01-09 23:43:55

+0

您可以在不同文件中的部分类中实现接口,而无需修改T4(除非添加“partial”关键字(如果它不存在) – SLaks 2012-01-09 23:47:20

+0

您提醒我已经修改了模板以添加“部分”关键字,所以我认为修改模板不应该那么困难,以便所有实体都可以从IEntity(您建议添加的接口)派生出来,我也这样做了,现在一切都编译好了。谢谢! – 2012-01-10 00:03:34

5

把你删除属性为接口(比方说,IDeleteable),并与通用约束限制类:

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

public abstract class RepositoryBase<T> where T : class, IDeleteable 

编辑:我认为这是暗示,但是你需要实现接口你的实体类,例如

public class Person : IDeleteable { ... } 
+0

@Chris_Shain我试过你的解决方案,但后来在编译时遇到了一个错误。看到我上面的更新看到我的错误。 – 2012-01-09 23:55:29

+0

您需要实际*实现*在所有实体类中的接口... – 2012-01-10 00:08:41

+0

@Chris_Shain谢谢,我终于做到了,现在它正在工作。我给了SLaks正确的答案,因为他首先提出了解决方案,但我给了你+1来编写一些例子代码。谢谢! – 2012-01-10 00:12:16

3

您可以使用抽象类的约束

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

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

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

+0

+1是为了使用抽象基类的理由。 – 2012-01-09 22:39:43

+0

@oleksii:我试过这个解决方案,它看起来不错,但后来我在编译时遇到了另一个问题。看到我的更新上面的具体错误消息。 – 2012-01-09 23:41:23

1

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

entity.Deleted = true; 

将被替换成:

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