2017-03-10 5 views
1

背景:DBテーブル/モデル/クラスをできるだけ効率的に妥当なものにし、そのパブリックプロパティをすべてフィルタ/並べ替え/表示できるようにする必要があります。アクセッサFuncをリフレクションしてDictionaryにインポートする

名前はreflection-APIによって照会することができますが、これらのアクセスを保存して効率的になるかどうかは疑問でしたか?

この例は、どのように実行できるかを示していますが、すべてのアクセスでfuncのreflection-apiにクエリを実行します。

public class TestClass // the Model or Table 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public static void Main(string[] args) 
{ 
    var testClasses = new TestClass[] { 
     new TestClass { Id = 1 , Name = "1" } , 
     new TestClass { Id = 2 , Name = "2" } , 
     new TestClass { Id = 3 , Name = "3" } , 
    }; 

    var propertyInfos = typeof(TestClass).GetProperties(); 
    var map = new Dictionary<string,Func<object,object>>(); // Func<object,object> -> Func takes an instance of the class and return a public property 

    // load the map once 
    foreach(var propertyInfo in propertyInfos) 
    { 
     Func<object,object> func = x => propertyInfo.GetValue(x); 

     map.Add(propertyInfo.Name , func); 
    } 

    // get the names by user-input 
    var names = propertyInfos.Select(x => x.Name).ToArray(); 

    // load the properties by name 
    foreach(var testClass in testClasses) 
    { 
     Console.WriteLine($"{testClass.Id} - {testClass.Name}"); 

     foreach(var name in names) 
     { 
      var func = map[ name ]; 
      var value = func(testClass); // this is 'bad' as it uses reflection every invokation 

      Console.WriteLine($"\t{name} = {value}"); 
     } 
    } 
} 

私の質問は次のようになります。この辞書

var map = new Dictionary<string,Func<object,object>> { 
    { "Id"  , x => (x as TestClass).Id } , 
    { "Name" , x => (x as TestClass).Name } , 
}; 

だけの種類を提供することにより、(各invokationにリフレクションを使用せずに)自動的に作成することができますか?

+0

提案したようにすると、C#-side行をフィルタリングします。WHEREを使用するSQLクエリは生成されません。あなたのC#コードは、テーブルのすべての行を受け取って、それらをフィルタリングします:-( – xanatos

+0

一般的に、それを「正しく」行う方法は、DBへのクエリをどのように行うかによって異なります。* Ado.NET *( 'DbConnection'または' DbCommand'や 'SqlCommand'を使った' SqlConnection')と文字列でクエリを書くと解決策のセットがありますEntity Framework、Linq-to-SQL、NHibernateを使用すると – xanatos

+0

良い点です。残念ながら、私はフィルタリングの前にそれらを前処理しなければならないので、レコードをメモリにロードする必要があります(元のテーブル表現を変更したり、前処理されたバージョンを別のテーブルに保存することはできません)。 C#Funcsのストアドプロシージャのように、 – nonsensation

答えて

2

あなたはそれぞれの呼び出しからの反射を除去して、一度だけ、それをすることによって何かを得ることができます:

var par = Expression.Parameter(typeof(object), "row"); 

// load the map once 
foreach (var propertyInfo in propertyInfos) 
{ 
    Func<object, object> func = Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Property(Expression.Convert(par, propertyInfo.DeclaringType), propertyInfo), typeof(object)), par).Compile(); 
    map.Add(propertyInfo.Name, func); 
} 

が、私はこの中で「正しい」タイプ( TestClassにパラメータオブジェクトをキャスト異なる小さな式ツリーを作成しますケース)、プロパティのゲッターを呼び出し、結果を objectに変換します。

関連する問題