2012-01-20 12 views
0

私はジェネリック型をとるために、私の基本クラスに抽象メソッドを定義しました。私ができるようにしたいのは、私のサブクラスの1つのリストをこの抽象メソッドに渡すことです。サブクラスでこれを正しく処理する方法がわかりません。ジェネリック型をリストにキャストする方法

基本クラスの抽象メソッド:

protected abstract void Validate<T>(T records); 

サブクラス実装(どこで問題が生じています):

コール法(LogEventRecordのリストを渡し):

Validate<List<LogEventRecord>>(records); 

メソッド(LogEventRecordのリストを処理したい):

 protected override void Validate<T>(T records) 
     { 
      //How do I handle records here? I want them to be List<LogEventRecord> and when i debug 
      //They appear to be coming in that way, but I can't utilize them in the method 
      //How do I cast the records to List<LogEventRecord>? Is that what I do? 

     } 

ご意見をいただければ幸いです。

答えて

5

は、このような方法で宣言します。

protected abstract void Validate<T>(IEnumerable<T> records) 

をそして、このようにそれを呼び出す:コンパイラは、ジェネリックメソッドの型は、明示的にこれを含める必要はありませんを推測することができるはず

Validate(records); 

。あなたは本当に種類や型推論が、何らかの理由で失敗した場合(コンパイラがあなたに文句を言われますので、あなたがこのことを知っているだろう)を含むようにしたい場合は、この操作を行うことができます。

Validate<LogEventRecord>(records); 

次に、あなたの実装では、レコードを使用することができますこのような:

protected override void Validate<T>(IEnumerable<T> records) 
{ 
    //you can use a foreach loop 
    foreach (T record in records) 
    { 

    } 

    //Or "linq" operators: 
    bool isValid = records.Any(r => r.IsNotValid); 

    //Or linq query comprehension syntax: 
    bool isValid2 = (from r in records 
        where r.IsNotValid 
        select r).Any(); 

} 

しかし、今、あなたが知っている唯一のものは、およそTは、それがオブジェクトであるということです。あなたは "オブジェクト"型の変数をあまり使うことができないので、これはあまり有用ではありません。実際、.IsNotValidプロパティはおそらく存在しないため、サンプルの後の2つのオプションは今すぐ失敗します。

代わりに、この関数で使用するオブジェクトを記述するインターフェイスが必要です(おそらく既に存在しているかもしれません)。おそらく、常にログまたは共通の基本型のレコードのいずれかになります。その場合、2つの選択肢があります。 1つは、ジェネリックタイプを制約することです。

protected abstract void Validate<T>(IEnumerable<T> records) where T : MyRecordInterface 

他のオプションは、C#4で(あなたがの必要性を回避できるようになるIEnumerabe < T>などのインターフェイス上での分散のための新しいサポートがあるということです:あなたはこのようなあなたのメソッドのシグネチャを変更することでそれを行います。一般的な全くただのVisual Studio 2010以降では、.NET 4を使用していることを確認し、次のようにメソッドを宣言し、これを利用するには、ここの方法:

protected abstract void Validate(IEnumerable<MyRecordInterface> records) 

は、.NET 4が必要ではなく、以前のバージョンのフレームワークを対象としたC#4を使用しています。これはIEnumerable < T>インターフェイスの.Net 4バージョンが必要なためです。分散のための必要なサポートを含むように構築されています。

最後に、3番目のオプションがあります。

protected abstract void Validate<T>(IEnumerable<T> records, Func<T, bool> isValid) 

:あなたはそうのように、ブールにリスト内の各項目を変換するためにあなたの方法にdelegateパラメータを追加することができます。

protected override void Validate<T>(IEnumerable<T> records, Func<T, bool> isValid) 
{ 
    bool recordsAreValid = records.Any(r => !isValid(r)); 
} 

Validate(records, l => ((LogEventRecord)l).IsValid); 
6

本当にあなたのメソッドが間違った署名を持っているようです。パラメータ名がの複数のですが、それはちょうどTを受け入れているということを意味しています。私はそれが本当にすべきだと思う:

protected abstract void Validate<T>(IEnumerable<T> records); 

あなたの実装では、レコードを単純に反復することができます。サブクラスその後、

public class Foo<T> 
{ 
    protected abstract void Validate(IEnumerable<T> records); 
} 

う:あなたのサブクラスのみLogEventRecordのコレクションを検証することができれば、それはうまくあなた本当には、クラスの型パラメータの部分ではなく、方法の一部にする必要があることが考えられ、と述べました次のようになります。

public class Bar : Foo<LogRecord> 
{ 
    protected override void Validate(IEnumerable<LogRecord> records) 
    { 
     foreach (LogRecord record in records) 
     { 
      ... 
     } 
    } 
} 

これ以上のコンテキストがなくても適切かどうかは分かりません。 が適切でない場合は、をすぐに習得してください。クラスをもっと壊す必要がある可能性があります。

1

リストを明示的に使用することは、通常、私にとっては効果的です。

protected override void Validate<T>(List<T> records) 

コンパイラがそれを把握し、型パラメータなしでそれを呼び出す:Validate(records)

+0

のIList はほとんど常にをリストにpreferrableで、IEnumerableをはほとんどいつものIList にpreferrableです。 –

関連する問題