2012-05-31 96 views
0

我在通過泛型類型創建類的新實例時遇到問題。我試圖做的是有一個數據庫上下文,可以使用DBSet <>或FakeDBSet <>創建。 FakeDBSet將用於測試代碼中。我目前有一個完整的虛擬datacontext,但它是一個浪費,因爲唯一真正的區別是DBSet使用。我已經考慮使用Activator.CreateInstance()沒有多少運氣。如何使用通用類型創建類的實例

例子:

public class Album {} 
public class Artist {} 

public class MusicStoreContext 
{ 
    public IDbSet<Album> Albums { get; set; } 
    public IDbSet<Artist> Artists { get; set; } 

    public MusicStoreContext(Type dbSetType) 
    { 
     Albums = new (dbSetType)<Album>; 
     Artists = new (dbSetType)<Artist>; 
    } 

} 

public class Startup 
{ 
    public Startup() 
    { 
     // Production code would do something like this: 
     MusicStoreContext context = new MusicStoreContext(typeof(DbSet<>)); 

     // Test code would do something like this: 
     MusicStoreContext testContext = new MusicStoreContext(typeof(FakeDbSet<>)); 
    } 
} 

我也試過這樣的事情:

public class MusicStoreContext<T> where T : IDBSet 
{ 
    public IDbSet<Album> Albums { get; set; } 
    public IDbSet<Artist> Artists { get; set; } 
    ... 

這裏是我想出了工作由於喬恩的建議:

public class MusicStoreContext 
{ 
    private IDbSet<Album> _Albums; 
    private IDbSet<Artist> _Artists; 

    public IDbSet<Album> Albums { get {return _Albums;} } 
    public IDbSet<Artist> Artists { get {return _Artists; } 

    public MusicStoreContext(Type dbSetType) 
    { 
     Albums = new (dbSetType)<Album>; 
     Artists = new (dbSetType)<Artist>; 
    } 

    public TaxDocumentsContext() : base() 
    { 
     CreateDbSets(new ProductionDbSetProvider()); 
    } 

    public TaxDocumentsContext(IDbSetProvider provider) 
    { 
     CreateDbSets(provider); 
    } 

    private void CreateDbSets(IDbSetProvider provider) 
    { 
     provider.CreateDbSet<Album>(this, ref _Albums); 
     provider.CreateDbSet<Artist>(this, ref _Artists); 
    } 

} 

而且對於DbSetProvider:

public interface IDbSetProvider 
{ 
    void CreateDbSet<T>(DbContext context, ref IDbSet<T> dbSet) where T : class; 
} 

public class FakeDbSetProvider : IDbSetProvider 
{ 
    public void CreateDbSet<T>(DbContext context, ref IDbSet<T> dbSet) where T : class 
    { 
     dbSet = new FakeDbSet<T>(); 
    } 

} 

public class ProductionDbSetProvider : IDbSetProvider 
{ 
    public void CreateDbSet<T>(DbContext context, ref IDbSet<T> dbSet) where T : class 
    { 
     dbSet = context.Set<T>(); 
    } 
} 

現在我可以很容易地不使用從這裏FakeDbSet擊中DB測試: http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

回答

5

編輯:如果有問題的設置有一個合適的構造函數,你可以使用Type.MakeGenericType創建相關的構造類型並使用Activator.CreateInstance調用構造函數:

Type albumType = dbSetType.MakeGenericType(typeof(Album)); 
Albums = (IDbSet<Album>) Activator.CreateInstance(albumType); 

或者,你可以在一個DbSetProvider通過(或其他),它有一個通用的方法:

public IDbSet<T> CreateDbSet<T>() 

,那麼你就會有一個ProductionDbSetProviderFakeDbSetProvider

public MusicStoreContext(DbSetProvider provider) 
{ 
    Albums = provider.CreateDbSet<Album>(); 
    Artists = provider.CreateDbSet<Artist>(); 
} 

個人,感覺清潔劑給我,但情況因人而異。

+0

喬恩,這沒有把戲。我不得不改變我的CreateDbSet()來處理DbSet沒有構造函數的事實。我已將更新的代碼添加到我的原始問題中。再次感謝。 –

+0

@JonSkeet在你的例子中變量'dbSetType'的上下文中。什麼是'dbSetType'?我的假設是'DbSet <>',但是如果您嘗試在EF 5.0中使用Activator.CreateInstance()創建'DbSet ',則會出現以下錯誤:'未找到類型的構造函數' –

+0

@JohnHartsock: DbSet <>'的具體子類。 –

相關問題