2016-06-15 12 views
1

クラスシステムを作成して、一部のデータソースからデータを取得してポスティングを一般化する必要があります。私は2つのメソッドを持っています:GetDataとPostData。両方のメソッドには何らかの入力が必要で、GetDataには戻り型も必要です。 ジェネリックインターフェイスの実装:汎用戻り型と汎用入力型

public class QueryParameter 
{ 
    public QueryParameter() 
    { 
     this.Direction = ParameterDirection.Input; 
    } 

    public string Name { get; set; } 
    public object Value { get; set; } 
    public ParameterDirection Direction { get; set; } 
} 

public class InputBase 
{ 
    public InputBase() 
    { 
     ResultMapping = new Dictionary<string, string>(); 
     Parameters = new List<QueryParameter>(); 
    } 
    public Dictionary<string, string> ResultMapping { get; set; } 
    public List<QueryParameter> Parameters { get; set; } 
} 
public class DatabaseInput: InputBase 
    { 
     public string Query { get; set; } 
     public DatabaseCommandType CommandType { get; set; } 
    } 

public interface IDataSource<I> where I: InputBase 
{ 
    IEnumerable<T> GetData<T>(I input); 
    void PostData(I Input); 
} 

は今、私はこのようなインターフェイスを実装してみました:私は、一般的なインタフェースを記述すると「DatabaseSource」クラスでそれを実装しようとした

public class DatabaseDataSource: IDataSource<DatabaseInput> 
{ 
    public IEnumerable<T> GetData<T>(DatabaseInput Input) 
    { 
     //implementation 
    } 

    public void PostData(DatabaseInput Input) 
    { 
     //implementation 
    } 
} 

しかし、私はデータをインスタンス化しようとすると、私は問題を抱えていますこのようなソース:

IDataSource<InputBase> dataSource = new DatabaseDataSource(); 

このコードは、ファクトリメソッドのいくつかの種類であると私は他のあるIDataSourceの実装をインスタンス化することができるはずですので、私はDatabaseInputを使用することはできません。

要するに、入力と出力をジェネリック型として、具体的なIDataSource実装と一致するようにInputを制約したいとします。

+0

これは、where演算子で行うことができます。http://stackoverflow.com/questions/1096568/how-can-i-use-interface-as-ac-sharp-generic-type-constraint –

+0

where演算子私の質問の最後のコードセクションのようにインスタンス化することはできません – vpetrovic

+0

'DatabaseDataSource'は' IDataSource 'ではなく、' IDataSource 'です。コンクリート型の共分散はできません。参照してください:https://msdn.microsoft.com/en-gb/library/dd799517(v=vs.110).aspx – TheInnerLight

答えて

0

制約の詳細については、where制約を使用して、hereをクリックします。

where T : class //The type argument must be a reference type; this applies also to any class, interface, delegate, or array type. 

where T : <interface name> //The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic. 
+0

彼はすでにこれを試しています、その意味は間違っています。 –

+0

私はどこの制約について知っていますが、それを構築することはできません。私はこれで具体的な例が必要です、私は私の質問で私の問題を記述し、あなたが見ることができるように、私は 'どこで'の定義を使用しようとしました。 – vpetrovic

3

私がこれを正しく理解しているとしたら、データソースは入力の両方の出力を定義する必要があります。あなたがこれを行う場合:

public IEnumerable<T> GetData<T>(DatabaseInput Input) 

は、そのメソッドの実際の実装は Tが何であるかに応じて大幅に異なる場合があります。 Tのタイプを検査してそれに応じてコードを分岐する場合、そのメソッドのシナリオは必要ありません。

はおそらく、あなたが望むものを、このようなものです:

public interface IDataSource<TInput, TOutput> where TInput: InputBase 
{ 
    IEnumerable<TOutput> GetData(TOutput input); 
    void PostData(TInput Input); 
} 

しかし、その後も次の2つの一見無関係な操作を定義するのインターフェイスを持っています。 (これはTInputがデータを変更/投稿するデータを取得するためのクエリとして、コマンドとしての両方で使用することができるとは考えにくい。)

ので、おそらくあなたはさらにそれを打破することができます:

public interface IDataSource<TInput, TOutput> where TInput: InputBase 
{ 
    IEnumerable<TOutput> GetData(TOutput input); 
} 

public interface IDataCommand<TInput> where TInput:InputBase 
{ 
    void PostData(TInput Input); 
} 

それをインスタンス化するにはあなたは抽象工場を使用することができます。

public interface IDataSourceFactory<TInput, TOutput> 
{ 
    IDataSource<TInput, TOutput> Create(); 
    void Release(IDataSource<TInput, TOutput> created); 
} 

それはあなたが、それは多少のインターフェイスを実装することを目的に反することを行う場合はvar dataSource = new [whatever].を呼び出すためにあなたのクラスの必要性を回避するためにその理由があります。 newを明示的に呼び出して特定のタイプを作成するとすぐに、実装するインターフェイスに関係なく、クラスはのに結合され、インターフェイスは結合されません。

元の問題が移動します。抽象的なファクトリの実装は何ですか?良いニュースは、工場に依存するクラスは、工場の実装が何であるか気にしないということです。しかし、あなたはまだそれを必要とします。それについての1つの方法は、DIコンテナを使用することです。 Windsorは、抽象ファクトリを作成するためのパターンを提供するので便利です。 This blog postはそれをより詳細に行う方法を説明しています。

+0

Scott、私はあなたの答えをより詳しく読むでしょう。 InputBaseが何であるかを明確にしたいだけです。これは、データをフィルタリングするためのパラメータを提供するための基本クラス(GetDataの場合)または更新クエリ(PostDataの場合)のパラメータです。 TResultについては、TResultオブジェクトでデータをロードするためにリフレクションを使用したいと考えています。 – vpetrovic

+0

それは私が考えたものです。 'public interface IDataSource ここでI:InputBase'を宣言し、そのメソッドが" get "と" post "の両方を持ち、両方がパラメータとして' I'を取ると、それはまったく同じ 'I' 'InputBase')は、照会パラメーターと更新/挿入/削除パラメーターの両方として使用可能でなければなりません。しかし、実際には、クエリパラメータが異なることになります。たとえば、エンティティに日付がある場合、クエリには開始日と終了日のパラメータが含まれますが、挿入コマンドまたは更新コマンドにはクエリの範囲ではなく実際の日付が入ります。 –