2010-12-13 24 views
1

私は、オブジェクトのプロパティの値を取得するために代理人を作成して再利用する必要があることを読んだ。Delegate.DynamicInvokeが遅すぎる、呼び出しを呼び出す方法を変更するには?

私は今、私は唯一の「DynamicInvoke」のコールでデリゲートを使用する方法を見つけるの委任

var objParm = Expression.Parameter(property.DeclaringType, "o"); 

    Type delegateType = typeof(Func<,>).MakeGenericType(property.DeclaringType, property.PropertyType); 

    var lambda = Expression.Lambda(delegateType, Expression.Property(objParm, property.Name), objParm); 

    return lambda.Compile() 

を作成するには、このコードを使用します。

私はパフォーマンスの理由の原因を「呼び出し」に変更したいと思います。

私は

Delegate.Method.Invoke(invokedObject, null); 

を試してみましたが、私は例外

MethodInfo must be a RuntimeMethodInfo. 

を得る呼び出しの後、私は私が動的に作成デリゲートを保存することができ、各プロパティのキャッシュクラスを持っています。

私は "normal" Invokesを使用することができますか?

ありがとうございます。

+1

「私は私がオブジェクトのプロパティの値を取得するためにデリゲートを作成し、再利用する必要があることを読みました。」非常にまれなケースでは、これは正しかった、「非常に」はここの術語である。ほとんどの場合、あなたは 'x.Property'だけですべきです。 – jason

+0

はい、まったく正しいです、説明の間違いでした。リフレクション(GetValue、SetValue)との一貫性を意味していました。 – Khh

+0

ここで問題となるのは、実行時にプロパティの名前が変わるだけでなく、型も変わるということです。これにより、高速の型セーフなデリゲート呼び出しの代わりに、スローリフレクションベースの呼び出しを使用する必要があります。 –

答えて

-1

名前をテキストとして使用してプロパティにアクセスする必要があるときに使用するクラスを作成しました。クラスはクラスのすべてのプロパティをキャッシュします。

使用法:

PropertyWrapper<User> wrapper = new PropertyWrapper<User>(); 
wrapper.SetValue("FirstName", "arne"); 
int age = (int)wrapper.GetValue("Age"); 

クラス

public class PropertyWrapper<T> 
{ 
    private Dictionary<string, Methods> _properties = new Dictionary<string, Methods>(); 
    private class Methods 
    { 
     public MethodBase Get { get; set; } 
     public MethodBase Set { get; set; } 
    } 

    public PropertyWrapper() 
    { 
     foreach (var item in typeof(T).GetProperties()) 
     { 
      if (!item.CanRead && !item.CanWrite) 
       continue; 

      var mappings = new Methods(); 
      if (item.CanRead) 
       mappings.Get = item.GetGetMethod(); 
      if (item.CanWrite) 
       mappings.Set = item.GetSetMethod(); 

      _properties.Add(item.Name, mappings); 
     } 
    } 

    public object GetValue(T instance, string name) 
    { 
     Methods mappings; 
     if (_properties.TryGetValue(name, out mappings) && mappings.Get != null) 
      return mappings.Get.Invoke(instance, null); 

     throw new MappingException("Specified property cannot be read", typeof(T), name); 
    } 

    public void SetValue(T instance, string name, object value) 
    { 
     Methods mappings; 
     if (_properties.TryGetValue(name, out mappings) && mappings.Set != null) 
     { 
      mappings.Set.Invoke(instance, new[] { value }); 
      return; 
     } 

     throw new MappingException("Specified property cannot be written.", typeof(T), name); 
    } 
} 

public class MappingException : Exception 
{ 
    public MappingException(string errMsg, Type type, string propertyName) 
     : base(errMsg) 
    { 
     ReflectedType = type; 
     PropertyName = propertyName; 
    } 

    public Type ReflectedType { get; private set; } 
    public string PropertyName { get; private set; } 
} 
+0

これはまだ遅いです。高性能を得るには、 'mappings.Set(instance、value)'を動作させる必要があります(つまり、型指定されていないパラメータ配列はありません)。 –

6

代わりにFunc<object,object>デリゲートを発行し、必要に応じてラムダ内でキャストし、結果を取得する必要があります。コンパイル時にデリゲートの型がわからない場合は、引数の種類や戻り値の型がわからないため、デリゲートを直接呼び出すことはできません。

また、property.GetGetMethod()の周りに代理人を作成することもできますので、ここで独自の方法をコンパイルする必要はありません。プロパティgetterメソッドを使用するだけです。

+0

ヒントのおかげで、素敵なコードの原因jgauffinの答えをマーク;) – Khh

関連する問題