1

汎用リポジトリを実装しましたが、エンティティ タイプが文字列である場合、実行時に適切なリポジトリを動的に作成する必要があります。

以下を使用してリポジトリを作成できました。

        Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
        Type entityType = common.GetType("Models.OneOfManyEntities");
        Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

        var repo = Activator.CreateInstance(repoType, new UnitOfWork());

ただしrepo、オブジェクトであり、実際にキャストしたいのですが、IRepository<TEntity>試してみIRepository<entityType>ましたが、正しくありません

これはレポのインターフェースです:

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
    IQueryable<TEntity> FindAll();
    IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
    TEntity FindById(object Id);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(object id);
    void Delete(TEntity entity);
}

リポジトリのアクティブ化されたインスタンスは正しい型ですが、Activator はオブジェクト型を返すため、メソッドを使用するにはそれをキャストする必要があります。

4

2 に答える 2

1

オブジェクトを にキャストしたいと言いますがIRepository<TEntity>TEntity実行時にしか利用できません (変数Type内のオブジェクトへの参照がありentityTypeます)。

可能であればIRepository<entityType>、次のようなメソッドから何が返されると思いますFindByIdか? おそらくentityTypeインスタンスだと思いますか?現在、任意の型であり、実行時にのみ決定されるため、コンパイラは変数entityTypeを含むコードをコンパイルする方法を認識できない可能性があります。entityTypeしたがって、IRepository<entityType>できません。

達成したい内容に応じて、2 つの解決策が考えられます。

  1. エンティティ オブジェクトについて知る必要があるコードを実行したくない場合はIRepository、型のエンティティを処理する追加の のようなインターフェイスを実装します (現在の に一致しないものが追加された場合は sobjectをスローする可能性があります)。呼び出しの結果をその新しいインターフェイス タイプにキャストします。ArgumentExceptionentityTypeActivator.CreateInstance
  2. エンティティ型をジェネリック引数として受け取る新しいジェネリック クラスを作成します。エンティティとリポジトリを処理するすべてのコードをその新しいクラスに移動します。この新しいクラスでは、ジェネリック引数として提供されたエンティティ タイプが常に使用されます。Activator.CreateInstanceクラスで直接行っていることと同様に、そのジェネリック クラスをインスタンス化しますTradeSiftRepository<T>
于 2012-07-31T11:17:11.053 に答える
0

あなたが求めていることは不可能だと思います。コードがジェネリック型パラメーターを表す文字列を受け取っている場合、それが表す型は実行時にのみ決定できます。ただし、ジェネリック型パラメーターはコンパイル時に指定する必要があります。

戻り値の型の型パラメーターとして使用する場合は、エンティティの型をジェネリック型パラメーターとして受け取る必要があると思います。

public IRepository<TEntity> MakeRepository<TEntity>() where TEntity : class
{
    var repo = new TradeSiftRepository<TEntity>(new UnitOfWork());
    return repo;
}

IRepository<User> userRepository = MakeRepository<User>();

エンティティ型名を文字列として確実に受け取りたい場合は、コンパイル時に結果を実際の型にキャストする責任は、コードを呼び出すことによって行う必要があります。これは、呼び出し元のコードが型を指定するものであるためです。

public object MakeRepository(string entityTypeName)
{
    Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
    Type entityType = common.GetType(entityTypeName);
    Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

    var repo = Activator.CreateInstance(repoType, new UnitOfWork());
    return repo;
}

IRepository<User> userRepository = (IRepository<User>)MakeRepository("User");

ただし、上記のコードは、汎用バージョンのメソッドを使用することで簡略化できます。重複が少ない。呼び出し元のコードも要求している型がわからない場合は、選択肢がないと思います。

考えられる回避策の 1 つは、動的な型を返すことです。これにより、呼び出し元のコードは、作成者が必要とする型のオブジェクトを持っていると想定することになります。

public dynamic MakeRepository(string entityTypeName)
{
    Assembly common = Assembly.LoadFrom(@"CommonLibrary.dll");
    Type entityType = common.GetType(entityTypeName);
    Type repoType = typeof(TradeSiftRepository<>).MakeGenericType(entityType);

    var repo = Activator.CreateInstance(repoType, new UnitOfWork());
    return repo;
}

dynamic userRepository = MakeRepository("ConsoleApplication1.User");
User user = userRepository.FindById(1);
于 2012-07-31T11:48:18.577 に答える