2009-07-30 9 views
7

かなり静的なデータを再評価するのではなく、キャッシュする代わりに、リフレクションを使用して一度クラスのプロパティを取得できるかどうかを疑問に思っていました。オブジェクトのプロパティと読み取り/割り当ての値は、私はそれを行うたびに反射のオーバーヘッドを持っていません。これは可能ですか(サンプルコード?)ビットを明確にするためにキャッシュリフレクションの結果(クラスのプロパティ)

、私はこのクラスを持って言うことができます:

public class Cloud 
{ 
    Boolean IsWhite; 
} 

と私は今、私はこのような何か(擬似コード)を行うことができます方法を作るしようとしている:

Update(myCloudInstance, new {IsWhite, true}); 

クラウドのプロパティ(typeof(myCloudInstance))が既にわかっている場合は、最初にキャッシュで確認してから、キャッシュされた情報を使用してReflectionを再実行する代わりにプロパティ "IsWhite"に値 "true"を割り当てます。

これを行う方法に関するアイデアはありますか?

答えて

7

明白ではありません正確にはあなたは何をしているのですか。しかし、キャッシングは確かに反映に違いを生むことができます。

特に、メソッド(またはプロパティゲッター/セッター)を呼び出すときに、呼び出し側コードに関する限り型保証された方法で行うことができる場合は、を強く依存するコードに変換すると、can make a huge difference、一度型付きの代理人を指定してから再利用してください。

私たちにあなたがしようとしていることの完全な例を与えることができれば、より具体的なアイデアやコード作成に役立ちます。 PropertyInfoをキャッシュするだけであれば、それほど効果がないかもしれません。通常のType.GetProperty(など)メソッドはすでにかなり高速になっている可能性があります。これまでのパフォーマンスの質問と同様に、キーは実際に行っていることを測定することです。変更を加えて再度測定するなど。

+0

実際にはGetPropertyよりも速い(PropertyInfoをキャッシュする方法)が私には示唆されていましたが、まだそれほど時間はかかりませんでしたが、ページの応答性は向上しています。 – Alex

+0

代理人をキャッシュしてタイプセーフな方法で、それはもう一度速くすることができます。間違いなくそれを時間... –

2

あなたが思うほどの費用を要しません。 - 代表者(ジョンは説明していること)あなたも多くのコードを変更することなく、反射のコストを最小限に抑えるHyperDescriptorのようなものを使用することができることに加えて、それは単にPropertyDescriptor代わりに次のようになります。その後、

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(myCloudInstance); 
// ideally cache props, but not essential 

object val = props["IsWhite"].GetValue(myCloudInstance); 

かそれをたくさん使う場合は、PropertyDescriptorもどこかに保管することを検討してください。

しかし、ジョンのように、私は本当にあなたがしようとしていることを100%確信していません!

0

ダイナミックアセンブリは、反射性能の懸念に役立ちます。誰かがダイナミックアセンブリhereを使ってプロパティアセスメントを実装しました。

1

私はそれを行うための最善の方法は、ゲッターやセッターメソッドを取得デリゲートに変換し、デリゲートで動作するようです、何より高速な方法はありませんと思う:

PropertyInfo propertyInfoProperty1 = type.GetType().GetProperty("Property1"); 
Func<TYPE, string> get_Property1 = (Func<TYPE, string>)Delegate.CreateDelegate(typeof(Func<TYPE, string>), propertyInfoProperty1.GetGetMethod()); 

その後ゲッターを呼び出しますメソッド:

string value = get_Property1(type); 

デリゲートをキャッシュできます。

2

私は、反映結果をキャッシュするためのハッシュテーブルを作成しました。初めて、GetPropertiesを呼び出し、その結果をhastableに保存する必要があります。次回は、まずPropertyInfoオブジェクトのListのハッシュテーブルをチェックしてください。存在する場合は、それを使用します。そうでなければ、GetPropertiesを呼び出します。

これを使用して、データウェアハウスをエンティティのリストにマップします。

私の実装は、Nick Harrison(http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/)のA Defense on Reflection in .Netに基づいています。

だから、そこにそれがある:だから

public List <Entities.ENFactura> ListaxIdFactura (SqlTransaction Tr, Entities.ENFactura oBEFactura) 
{ 

    SqlConnection Cn = new SqlConnection(); 
    Cn = _Connection.ConexionSEG(); 

    List<Entities.ENFactura> loBEFactura = new List<Entities.ENFactura>(); 

    using (Cn) 
    { 
     Cn.Open(); 
     SqlDataReader drd = (odaSQL.fSelDrd(Cn, Tr, "Pa_CC_Factura_Listar_x_IdProveedor", oBEFactura)); 
     if (drd != null) 
     { 
      if (drd.HasRows) 
      { 
       mapeador.MapearDataReaderListaObjetos <ENFactura>(drd, loBEFactura); 
      } 
     } 
    } 
    return (loBEFactura); 
} 

、この方法は、DALは、DataReaderオブジェクトを取得し、それをマップ:

その後
public class MapeadorDataReaderListaObjetos 
{ 

    private Hashtable properties; 

    private Hashtable Properties 
    { 
     get 
     { 
      if (properties == null) 
       properties = new Hashtable(); 
      return properties; 
     } 
     set { properties = value; } 
    } 

    private void LoadProperties(object targetObject, Type targetType) 
    { 
     var flags = BindingFlags.DeclaredOnly| BindingFlags.Instance| BindingFlags.Public; 

     if (properties == null) 
     { 
      List<PropertyInfo> propertyList = new List<PropertyInfo>(); 
      PropertyInfo[] objectProperties = targetType.GetProperties(flags); 
      foreach (PropertyInfo currentProperty in objectProperties) 
      { 
       propertyList.Add(currentProperty); 
      } 
      properties = new Hashtable(); 
      properties[targetType.FullName] = propertyList; 
     } 

     if (properties[targetType.FullName] == null) 
     { 
      List<PropertyInfo> propertyList = new List<PropertyInfo>(); 
      PropertyInfo[] objectProperties = targetType.GetProperties(flags); 
      foreach (PropertyInfo currentProperty in objectProperties) 
      { 
       propertyList.Add(currentProperty); 
      } 
      properties[targetType.FullName] = propertyList; 
     } 
    } 

    public void MapearDataReaderListaObjetos <T> (IDataReader dr, List<T> lista) where T: new() 
    { 
     Type businessEntityType = typeof(T); 
     List<T> entitys = new List<T>(); 
     T miObjeto = new T(); 
     LoadProperties(miObjeto, businessEntityType); 
     List<PropertyInfo> sourcePoperties = Properties[businessEntityType.FullName] as List<PropertyInfo>; 

     while (dr.Read()) 
     { 
      T newObject = new T(); 
      for (int index = 0; index < dr.FieldCount; index++) 
      { 
       for (int _indice = 0; _indice < sourcePoperties.Count; _indice++) 
       { 
        if (sourcePoperties[_indice].Name.ToUpper() == dr.GetName(index).ToUpper()); 
        { 
         string _tipoProp = sourcePoperties[_indice].PropertyType.ToString(); 
         PropertyInfo info = sourcePoperties[_indice] as PropertyInfo; 
         if ((info != null) && info.CanWrite) 
         { 
          info.SetValue(newObject, dr.GetValue(index), null); 
         } 
        } 
       } 
      } 
      entitys.Add(newObject); 
     } 
     dr.Close(); 
     lista = entitys; 
    } 
} 

、私はこのように、私のDataAccesレイヤからそれを呼び出しますビジネスエンティティのリストに追加し、それをビジネスロジックレイヤーに戻します。

info.SetValue(newObject, _valor, null); 

でnewObjectと_valorは同じ型でなければならないか、例外(可能System.Int32へSystem.Int64からの変換を、取得します:

このクラス(MapeadorDataReaderListaObjetos)は特にで、まだいくつかの問題を持っていますエンティティプロパティがInt32で、データベーステーブルの対応するフィールドがbigintの場合など)。

また、エンティティプロパティが別のエンティティである場合、データプレイヤーはエンティティオブジェクトを返さないため、これは機能しません。

これは明らかに改善することができます。

反射と代議員に関して、私はこの記事を見つけました:Reflection - SlowまたはFast?ソリューションによるデモンストレーションは、アビシェーク・スルによって、 http://www.abhisheksur.com/2010/11/reflection-slow-or-faster-demonstration.html

で別の良い記事があります:Dodge一般的なパフォーマンスの落とし穴http://msdn.microsoft.com/en-us/magazine/cc163759.aspxで、ジョエルPobarにより、スピーディアプリケーションを作るために。

これが役に立ちます。

関連する問題