2

インターフェイスを型として取得するジェネリック関数がありますが、ある条件では、インターフェイスに応じて新しいクラスを作成する必要があります。私はそれについて考えていて、それを解決する方法はIoCを使用することですが、IoCは少しやり過ぎのように見えるので、別の方法があることを望んでいました。

以下は、ビジターパターンを使用した試みです。

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, new()
{
    public T GetOrCreate(string id)
    {
        T item = (T)CreateNew(new T(), id);
        return item;
    }
}

インターフェイスの代わりにオブジェクトを取得している場合は、ビジターパターンを使用してインスタンス化するクラスを把握できますが、提供されているインターフェイスによってはこれを把握できないようです。

私が持っていた他のアイデアは、またはのようなwhere宣言を行うことができるかどうかでした。

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, Iabc or Ixyz, new()

質問が明確であることを願っています:)

-マーク


返信ありがとうございます。

問題は、メソッドに多くの異なるインターフェースを割り当てることができることです。たとえば、次のようになります。

RepositoryManagerクラス:

private static IMedicament CreateNew(IMedicament emptyType, string id)
{
    return new Medicament { Id = id };
}
private static IRefund CreateNew(IRefund emptyType, string id)
{
    return new Refund { Id = id };
}

RepositoryManager<Iabc> abcRepository = new RepositoryManager<Iabc>();
RepositoryManager<Ixyz> xyzRepository = new RepositoryManager<Ixyz>();

Iabc abc = abcRepository.GetOrCreate("12345");
Ixyz xyz = xyzRepository.GetOrCreate("12345");

したがって、TはタイプIabcまたはIxyzのいずれかである可能性があることを通知する必要があるため、使用T item = (T)CreateNew(new T(), id);は機能しませんが、これを行うと、次のエラーが発生します。

次のメソッドまたはプロパティ間で呼び出しがあいまいですRepositoryManager<T>.CreateNew(IMedicament, string)RepositoryManager<T>.CreateNew(IRefund, string)

コードを数回コピーするだけでなく、これが機能するようになればいいのですが。

4

6 に答える 6

2

そして、なぜこれが機能しないのですか?

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz, new()
{
    public T GetOrCreate(string id)
    {
        T item = (T)CreateNew(new T(), id);
        return item;
    }
}

new()を使用できない場合の別の方法は、デリゲートを渡してオブジェクト(または互換性のあるタイプ)を作成することです。

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz
{
    private Func<T> _tConstructor;

    public RepositoryManager(Func<T> tConstructor)
    {
      this._tConstructor = tConstructor;
    }

    public T GetOrCreate(string id, )
    {
        T item = (T)CreateNew(this._tConstructor(), id);
        return item;
    }
}
于 2008-11-20T02:24:59.247 に答える
2

質問を完全に理解しているかどうかはわかりませんが、以前にこのようなものを使用したことがあります。

public class Repository
{
    public T Create<T>(string id) where T : class
    {
        return Activator.CreateInstance(typeof(T), new[] { id }) as T;
    }
}
于 2008-11-20T03:04:34.643 に答える
1

あなたの質問が何であるかを理解していれば、RhinoMocks が実際にインターフェースからクラスを動的に作成することを除いて、基本的には (ある意味で) RhinoMocks と同じことをしたいと考えています。

RhinoMocks がこれをどのように実現するかを知るには、コードに精通していませんが、オープンソースであるため、ソース コードを見ればいくつかのアイデアを得ることができるかもしれません。

http://ayende.com/projects/rhino-mocks/downloads.aspx

于 2008-11-20T01:58:06.960 に答える
1

IRefund と IMedicament に、両方とも Id プロパティを持つ共有インターフェイスを実装させるのはどうですか?

于 2009-05-29T19:45:13.407 に答える
0

先日、自分でこの問題に遭遇しました。問題は、コンストラクターが取るパラメーターの数がわからないということです。何も取らないと仮定すると、次のコードが機能します。

public void Method<T>()
{
  Type type = typeof(T);

  T newObject = (T)type.GetConstructor(new System.Type[] { }).Invoke(new object[] { });
}

この例では、リフレクションを使用しています。パラメータが必要な場合は、コードで作成された配列にオブジェクトを配置できます。

于 2008-11-20T02:19:01.757 に答える
0

たぶん、次のことがうまくいくでしょうか?1) type がインターフェイス (T パラメータ) であり、object が作成可能なオブジェクトのダミー インスタンスである辞書を作成します。2) ダミー オブジェクトを、T を実装する新しいオブジェクトのファクトリにします。

RepositoryManager は、サポートされているインターフェイスとオブジェクトのペアでディクショナリを初期化するだけでよく、複数のインターフェイスが同じオブジェクトにマップできます (必要な場合)。

于 2010-08-25T15:27:59.847 に答える