2017-02-14 14 views
0

パラメータに渡されるジェネリック型に基づいてこの式を動的にするにはどうすればよいですか?簡略化した形でジェネリック型に基づいて動的述語を構築する

public static class CompareService 
{ 

    public static List<T> Run<T>(List<T> database_list, string directory_path) 
    {   
      var csv_list = CompareService.MergeRecordsFromFiles<T>(directory); 
      return CompareService.RunComparison<T>(database_list, csv_list); 
    } 

    public static T CompareData<T>(List<T> database_list, List<T> csv_list) 
    {   
      var diff = new List<T>(); 

      foreach (var db_item in database_list) 
      { 
       // ... 
       // if T is of type Deathstar compare reference_number property 
       // if T is of type Stormtrooper compare id property 
       // if T is of type Sith compare id and anger_level property     
       var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number); 
       // Comparison code 
       ComparisonResult result = compareLogic.Compare(db_item, csv_item); 
       // ... 
      } 
      return diff; 
    }  
} 

別の汎用サービスから呼び出される:最も単純な実装では、あなたのitemToFindDeathStarにキャストできるかどうかを確認することです

public static void Whatever<T>(List<T> list) 
{ 
    // ... 
    var directory_path = "C:\"; 
    var delta = CompareService.CompareData<T>(list, directory_path); 
    // ... 
} 
+1

メソッドの命名は正確ではありません。おそらくあなたはそれを 'GetByReferenceNumber()'またはそれに類するものと呼ぶつもりでしたか?また、これは 'Where()'節を 'FirstOrDefault()'で直接置き換えることができることを意味します。 – silkfire

+2

あなたはタイプミスがありますか? 'list'パラメータは関数の本体で' database_list'ですか? –

+0

また、ユースケースについてさらに詳しく説明する必要があると思います。 –

答えて

2

StormTrooperSith、そうであればinstancesプロパティを呼び出します。

var deathStar = itemToFind as DeathStar; 
if(deathStar != null) 
    return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault(); 
else 
{ 
    var sith = itemToFind as Sith; 
    if(sith != null) 
     return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault(); 
    else 
     return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault(); 
} 

これは、多くのキャストを含む非常に面倒です。特に、任意の型を使用してジェネリックの実際の利点を完全にバイパスします(既存の場合は制約を満たします)。あなたのケースでは、3つのまともなタイプのためにのみwortkする一般的な方法があります。

より良いアプローチは、すべてのクラスは、例えば、プロパティを定義する共通のインタフェースを実装できるようにすることです:

interface IObject { 
    int Level { get; } 
} 

は今、すべてのクラスを定義することlevel -property:あなたより

clas DeathStar : IObject 
{ 
    public int Level { get { return this.reference_number; } } 
} 
clas Sith : IObject 
{ 
    public int Level { get { return this.anger_level; } } 
} 
clas StormTrooper: IObject 
{ 
    public int Level { get { return this.id; } } 
} 

タイプTの制約を使用して、そのインターフェイスを実装することができます。

+0

私は第2のアプローチが好きです。しかし、最初は本当に奇妙で、_generic_メソッドを宣言してから、そのタイプが(私にとっては)典型的には設計上の欠陥の兆候であると感じます。 –

+0

@RenéVogt確かに、それは最も素朴な実装であり、必然的に最高のものではありません。 – HimBromBeere

+0

Tが一般的で、reference_numberまたは任意のプロパティの定義が含まれていないため、最初のアプローチは機能しません。 –

0

なぜ、このようにしない:

public static T CompareData<T>(List<T> list, Func<T, bool> predicate) 
{ 
    return database_list.FirstOrDefault(predicate); 
} 

をし、このようにそれを使用します。

var itemToFind = new ItemToFind(); 
var myObjectList = new List<MyObject>(); 
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id); 
+0

なぜ彼はあなたの関数を必要としますか?彼は直接 'database_list.FirstOrDefault(x => x.MyObjectProperty == itemToFind.Id)'を使用することができます。 –

+0

真ですが、彼の説明は具体的ではありませんでした。この関数は、動的メソッドを公開するサービスインターフェイスの拡張メソッドまたはサービスインプリメンテーションにする場合に便利です。 –

+0

あなたは 'T itemToFind'パラメータを取り出しました。 –

0

あなたは、プロパティセレクタ追加することができます。

public static class CompareService 
{ 
    public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector) 
    { 
     int propToFind = propSelector(itemToFind); // cache 
     return database_list.FirstOrDefault(x => propSelector(x) == propToFind); 
    } 
} 

をそして、そのようにそれを呼び出す:

listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number); 
listOfStormtroopers.CompareData(trooperToFind, t => t.id); 
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level}); 

注:thisというキーワードを署名に追加して拡張機能にしました(キーワードを忘れていたかどうかはわかりません)。 Where(predicate).FirstOrDefault()FirstOrDefault(predicate)に減らすことができます。

関連する問題