2016-09-20 26 views
1

ORMエンティティのデータをデータセットに転送するコードを記述しています。私は現在、リフレクションを使用しています(エンティティのタイプでGetPropertiesを呼び出し、このタイプのDataTableを構築してから、各PropertyinfoでGetValueを呼び出しています)。各エンティティ)。現状:それは動作しますが、遅いです。反射によって取得されたプロパティの値を取得する関数を作成する

今、私は特定のプロパティの値を高速に取得する関数を返すメソッドを構築しようとしていますが、ここでは苦労しています。これは私がこれまでに得たものである:

/// <summary> 
    /// creates a func that will return the value of the given property 
    /// </summary> 
    /// <typeparam name="T">type of the entity</typeparam> 
    /// <param name="propertyInfo">the property to get the value from</param> 
    /// <returns>a function accepting an instance of T and returning the value of the property</returns> 
    private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo) 
    {   
    MethodInfo getMethod = propertyInfo.GetGetMethod(); 
    return (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), getMethod);   
    } 

これらは私のユニットテストです:

[TestMethod] 
    public void TestGenerateDelegate() 
    { 
    var employee = new Employee 
    {    
     Id = 1, 
     Name = "TestEmployee",    
    }; 

    Func<Employee, object> getIdValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Id")); 
    Assert.AreEqual(1, getIdValueFunc(employee)); 
    } 

    [TestMethod] 
    public void TestGenerateDelegateName() 
    { 
     var employee = new Employee 
     { 
      Name = "Test" 
     }; 

     Func<Employee, object> getNameValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Name")); 
     Assert.AreEqual("Test", getNameValueFunc(employee)); 
    } 

「ターゲット・メソッドへの結合中に例外」私は最初のもの、メッセージとともにArgumentExceptionがを呼び出す

(翻訳された、異なるテキストかもしれない)がスローされます。 2回目のテストは代わりに実行されます。

私はかなり私はそのCreateDelegateメソッドを正しく処理していないと確信しています。誰も私を正しい方向に向けることができますか?

更新:

PetSerAIのstatetとして、プリミティブ型は、CreateDelegateを経由してオブジェクトとして返すことができない値、分散の問題のようです...

+1

委任戻り値の型の分散が値型では動作しません。 'int'を返すメソッドをバインドして、' object'を返すことを委譲することはできません。 – PetSerAl

+0

あなたは正しいですが、Idプロパティでは動作しません。なんて残念なこと、惜しいこと! – Udontknow

答えて

1

あなたは指定されたプロパティを参照され、動的にデリゲートを作成するために、式ツリーを使用することができます。

private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo) { 
    ParameterExpression p = Expression.Parameter(typeof(T)); 
    return Expression.Lambda<Func<T, object>>(
     Expression.Convert(Expression.Property(p, propertyInfo), typeof(object)), 
     p 
    ).Compile(); 
} 
+0

偉大な、それは働いている。どうもありがとう! – Udontknow

2

あなたは自分のgetMethodを呼び出すことができます。

private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo) 
{ 
    MethodInfo getMethod = propertyInfo.GetGetMethod(); 
    return o => getMethod.Invoke(o, BindingFlags.Default, null, null, CultureInfo.CurrentCulture); 
} 
+0

それはドイツ人が「危険な半知識」と呼んでいるかもしれませんが、methodinfo経由で直接呼び出しに比べて遅い呼び出しではありませんか?それは私が避けたいものです... – Udontknow

0

genericジェネリックに行き渡ってコンパイラに代理人を作成させてみませんか?

その後
public static class Ext 
{ 
    public static Func<T, TProp> CreateGetPropertyFunc<T, TProp>(this T obj, Func<T, TProp> func) 
    { 
     return func; 
    } 
} 

var getterForId = employee.CreateGetPropertyFunc(x => x.Id); 
int result = getterForId(employee); 
// result can now be 'int' and doesn't have to be 'object' 

あなたは先行Tの実際のインスタンスを持っていない、あるいは単に拡張メソッドのアプローチをしたくない場合は、次の

public Func<T, object> CreateGetPropertyFunc<T>(Func<T, object> func) 
{ 
    return func; 
} 

次に:

var getterForId = CreateGetPropertyFunc<Employee>(x => x.Id); 
object result = getterForId(employee); 
// result must be 'object' (unless explicitly casted) 

intのような値-種類箱入り得ることはありませんし、型の安全性が保たれているので、前者はパフォーマンスの面で優れている)の静的メソッドへ

+0

私はあなたを誤解するかもしれません。私は持っているすべてのエンティティプロパティのすべての行を記述したくない。私は、リフレクションによってタイプのすべてのプロパティを動的に取得し、プロパティ値を抽出する高速アクセスメソッドを作成したいと考えています。ラムダ "x => x.Id"を書くポイントは何ですか?イド? – Udontknow

+0

@Udontknow、 "Lambdaを書くことのポイント"は、コンパイラがあなたの望む 'Func <>'にそれを翻訳し、あなたはReflectionを使う必要がないということです。 ** 1)**パフォーマンス面では優れています** 2)**定義と実装の両方が短く、最も重要なのは** 3)**タイプの安全性を保持しています。 – haim770

+0

私はラムダの利点を理解しており、私は自分の目的を明確に説明していないと感じています。 DataSetに1つの拡張メソッドがあり、任意のオブジェクト(!)のデータをDataTableインスタンスに転送できるようにしたいと考えています。どのように私は設計時に知らないプロパティのラムダを書くのですか?それは反映が来るところです:-) – Udontknow

1

CreateDelegate(Type, MethodInfo)バインド(あなたは何の静的メソッドを持っていません、これはあなたがエラーを取得している理由である)

にのみ、このバージョンとインスタンスメソッドのためDelegate.CreateDelegateを使用することができます。CreateDelegate(Type, Object, MethodInfo)

指定された第1引数を使用して、指定された スタティックメソッドまたはインスタンスメソッドを表す、指定された型のデリゲートを作成します。PetSerAlさんのコメントを1として

https://msdn.microsoft.com/en-us/library/system.delegate.createdelegate(v=vs.110).aspx

、あなたはインスタンスを渡すことになるに「オープンデリゲート」を作成するために、「第一引数」として「ヌル」を渡す必要があります。

// In this case, the delegate has one more 
    // argument than the instance method; this argument comes 
    // at the beginning, and represents the hidden instance 
    // argument of the instance method. Use delegate type D1 
    // with instance method M1. 
    // 
    d1 = (D1) Delegate.CreateDelegate(typeof(D1), null, mi1); 

    // An instance of C must be passed in each time the 
    // delegate is invoked. 
    // 
    d1(c1, "Hello, World!"); 
+0

'CreateDelegate(Type、MethodInfo)'は非静的メソッドからデリゲートを作成できます: 'Delegate.CreateDelegate(typeof(Func <オブジェクト、文字列>)、typeof(オブジェクト).GetMethod(" ToString "))'。 [Docs](https://msdn.microsoft.com/library/53cz7sc6.aspx#Anchor_2)は次のように述べています。* .NET Framework Version 2.0では、このメソッドのオーバーロードにより、開いているインスタンスのメソッド代理人も作成できます。つまり、インスタンスメソッドの隠された最初の引数を明示的に提供する代理人* – PetSerAl

+0

ありがとう、私はそれを実現していない - したがって、彼は他のオーバーロードを使用する必要があります。私は自分の答えを適切に編集します。 –

関連する問題