0

ジェネリックを使用してタイプごとにクラスの新しいインスタンスを作成する際に問題が発生します。私がやろうとしているのは、DBSet<>またはFakeDBSet<>のいずれかで作成できるデータベースコンテキストを用意することです。FakeDBSetはテストコードで使用されます。私は現在完全な偽のデータコンテキストを持っていますが、唯一の本当の違いは使用される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 /

4

1 に答える 1

6

編集:問題のセットに適切なコンストラクターがある場合はType.MakeGenericType、関連する構築型を作成し、Activator.CreateInstance:を使用してコンストラクターを呼び出すことができます。

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

DbSetProviderまたは、ジェネリックメソッドを持つ(または何でも)を渡すことができます。

public IDbSet<T> CreateDbSet<T>()

次に、とがProductionDbSetProviderありますFakeDbSetProvider

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

個人的にはそれは私にはきれいに感じますが、YMMV。

于 2012-05-31T15:52:47.067 に答える