2012-01-09 123 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);