2

私はデータアクセス層を緩く結合して遊んでいます。依存性注入プロセスは非常に役立ちましたが、ジェネリックスの使用を検討する際に少し難問に遭遇しました。

ジェネリック型パラメーターをサポートするクラスを取得して、真に分離され、型に対して安全にする方法はありますか?私の懸念は、共通のインターフェイスに書き込んだとしても、派生した型が最初にコーディングしたエンティティと異なる場合、コンパイラがキャッチできない厄介なランタイムエラーが発生する可能性があることです。

問題は、データベースからデータを取得してオブジェクトをハイドレイトするコードを作成するときに、次のレイヤーに実装しようとすると難問に直面することです。以下のFoo2などのクラスを渡すと、「暗黙の」変換がないため、コードを壊す可能性があります。私はリフレクションを使って物事を緩めようとしていましたが、データベースからデータを取得するときに具体的なタイプをハイドレイトする必要があるという問題に戻ってきます。そのタイプは、キャストとタイプ保証に関する問題を引き起こします。さらに、エンティティライブラリ内の多くのタイプすべてのすべてのメソッドを抽象化する場合は、リフレクションを使用してこれを行うことができますが、ジェネリックは明示的に「where T:ISomeInterface」ステートメントでのみタイプ保証を行うことができるという問題が発生します。 。ついに、このモデルは、今後さらに派生型が存在する場合、またはインターフェイスから分岐して新しい型を形成する型がある場合に機能しなくなります。これまでに作成されたすべてのタイプに新しいデータアクセスオブジェクトを実装する必要があると考えると、データアクセス層に変更が強制されます。それは私の心の中の緩い結合の定義を破ります。

これらすべてが私を疑問に戻させているようです-ジェネリックは本当に緩い結合の方法で使用できますか?もしそうなら、あなたはどのような参考文献を提供できますか?

簡略化した例:

public interface IEntity
{
    // stuff for state and methods ...
}
public interface IRepository<T> where T : IEntity
{
    void Save(out int id, T obj);
    T Load(int id);
}
public interface IFoo : IEntity
{
    int Id { get; set; }
    //All other IEntities goodness
    //Some new goodness specific to Foo
}
//Concrete Entities:
public class Foo : IFoo
{
    // blah blah
}
public class Foo2 : IFoo
{
    // new blah blah
}

public class FooRepository : IRepository<Foo> //OOPS, Looks like we have settled in on a concrete type!
{

    public void Save(out int id, Foo obj)
    {
        // ADO.NET code to access Sql ...
        id = 1;// this would actually be the result of the Sql insert output parameter
        return;
    }

    public Foo Load(int id)
    {
        Foo foo = new Foo();
        // ADO.Net code to access Sql
        return foo;
    }
}

では、IFoo派生オブジェクトを処理でき、プログラマーが将来何をするかに関係なく、完全に形成された具象型を返すことができるコードをどのように処理しますか?ジェネリック部分を捨てて、依存性注入に固執するのが最善ですか?どんな参考文献、ガイダンスなども素晴らしいでしょう。

4

3 に答える 3

1

ここで発生している問題typeofでは、オブジェクトの動的タイプを取得するためにいつでも使用できます (または、おそらく別の演算子/メソッドです)。このようにして、キャスト エラーが発生する前に常にチェックを実行できます。

具象型の制限を最上位の型に設定することはできますが、それはジェネリックの目的を実際に無効にします。

そうでなければ、あなたの問題を克服する方法が本当にわかりません。ジェネリックを使用する場合のポイントは、型にとらわれない疎結合とジェネリック操作を追加することです。それを取得できる唯一の方法は、typeof してから再キャストし、エッジ ケースをキャッチしてキャスト エラーを防ぐことです。あなたの質問について:

ジェネリックは本当に疎結合の方法で使用できますか?

私はあなたが何を意味するのかよくわかりませんか?もちろん、あなたの質問から意味的にはできます。それは実際、ジェネリックの目的の 1 つです。

では、IFoo 派生オブジェクトを処理でき、プログラマーが将来何をしようとも、完全に形成された具象型を返すことができるコードをどのように扱うのでしょうか?

これもかなり曖昧です。私は書くことができます:

public SomeType method(IFoo obj)
{
...
}

そして、これはまだすべての IFoo を処理します。これにはジェネリックは必要ありません。渡したものの型を具体的に返したい場合は、次のようにします。

public T method<T>(IFoo obj) where T:IFoo
{
    return (T)obj;
}

お役に立てれば。何か問題が発生した場合はLMK。

于 2013-03-12T23:45:44.610 に答える
1

あなたの難問に少し混乱していることを認めなければなりません。それが何であるかはわかりません。

具象型を生成するリポジトリは、明らかにそれらの作成方法を知っている必要があります。それぞれが実装するようなタイプごとにリポジトリを作成してみませんIRepository<IFoo>か? そうすれば、具体的な実装を DI コンテナーの構成に任せることができます。

たとえば、ninject では次のようなものを書きます。

Bind<IRepository<IFoo>>.To<Foo2Repository>()

それを設定します。よりきめ細かい制御が必要な場合、私が知っているほとんどのコンテナは、特定の条件でのみバインディングが有効になるように、何らかの方法でスコープをサポートしています。

私は何かを誤解しましたか、それともこれはあなたの懸念に対処していますか?

于 2013-03-12T23:57:47.500 に答える
0

で共通のものを定義できます

class BaseFooRepository<TFoo> : IRepository<TFoo> where TFoo : IFoo

次に、より具体的なコードを入れます

class Foo2Repository : BaseFooRepository<Foo2>
于 2013-03-12T23:59:59.573 に答える