Cヒドイ高性能動的にオブジェクト属性値を取得するステップ


動的に対象の性能値を取得します。これは開発中によくあります。ここではどのように性能の高い属性値を取得するかを検討します。対比テストのために、私達は一つの種類のPeopleを定義します。

public class People
{
  public string Name { get; set; }
}
直接コードの呼び出しで1千万回取るとどれぐらいかかりますか?

private static void Directly()
{
  People people = new People { Name = "Wayne" };
  Stopwatch stopwatch = Stopwatch.StartNew();
  for (int i = 0; i < 10000000; i++)
  {
    object value = people.Name;
  }
  stopwatch.Stop();
  Console.WriteLine("Directly: {0}ms", stopwatch.ElapsedMilliseconds);
}
37 msぐらいかかりました

反射
反射によってオブジェクトの属性値を取得するのは一般的ですが、このような方法は性能が悪いです。次に私達は同じように1千万回取るとどれぐらいの時間がかかりますか?

private static void Reflection()
{
  People people = new People { Name = "Wayne" };
  Type type = typeof(People);
  PropertyInfo property = type.GetProperty("Name");
  Stopwatch stopwatch = Stopwatch.StartNew();
  for (int i = 0; i < 10000000; i++)
  {
    object value = property.GetValue(people);
  }
  stopwatch.Stop();
  Console.WriteLine("Reflection: {0}ms", stopwatch.ElapsedMilliseconds);
}
1533 msぐらいかかりましたが、やはり遅いです。

反射が遅いなら、他の方法がありますか?
ダイナミックビルディング
LinkqのLamban表現を動的に構築できることを知っています。コンパイルによって、属性値を返す依頼を動的に構築できれば、値を取ることができます。だから、私達はなんとかしてこのような依頼を構築します。

Func<People, object> getName = m => m.Name;
次に私達はExpressionを通じて構築します。

private static void Lambda()
{
  People people = new People { Name = "Wayne" };
  Type type = typeof(People);
  var parameter = Expression.Parameter(type, "m");//  m
  PropertyInfo property = type.GetProperty("Name");
  Expression expProperty = Expression.Property(parameter, property.Name);//      m.Name
  var propertyDelegateExpression = Expression.Lambda(expProperty, parameter);//      m => m.Name
  var propertyDelegate = (Func<People, object>)propertyDelegateExpression.Compile();//     
  Stopwatch stopwatch = Stopwatch.StartNew();
  for (int i = 0; i < 10000000; i++)
  {
    object value = propertyDelegate.Invoke(people);
  }
  stopwatch.Stop();
  Console.WriteLine("Lambda:{0}ms", stopwatch.ElapsedMilliseconds);
}
そしてテストしてみます。138 msぐらいかかりました。性能は反射よりずっといいです。

コールを依頼する
ランバーの性能はダイナミックに構築されましたが、いいですか?直接呼ぶよりも悪いので、属性の取得方法を直接に呼び出せばいいです。
C〓〓の中で、読み取り可能な属性はすべて1つの対応するget〓があります。XXX()の方法は、この方法を呼び出して属性の値を取得することができます。System.Delegate.CreateDelegateの作成依頼を使ってこの方法を呼び出すことができます。
  • 属性値
  • は、コールを依頼することによって取得される。
    私たちはMember GetDelegateの依頼を定義し、それによって取得方法を呼び出します。
    
    delegate object MemberGetDelegate(People p);
    private static void Delegate()
    {
      People people = new People { Name = "Wayne" };
      Type type = typeof(People);
      PropertyInfo property = type.GetProperty("Name");
      MemberGetDelegate memberGet = (MemberGetDelegate)System.Delegate.CreateDelegate(typeof(MemberGetDelegate), property.GetGetMethod());
      Stopwatch stopwatch = Stopwatch.StartNew();
      for (int i = 0; i < 10000000; i++)
      {
        object value = memberGet(people);
      }
      stopwatch.Stop();
      Console.WriteLine("Delegate: {0}ms", stopwatch.ElapsedMilliseconds);
    }
    そしてテストしてみます。大体38 msかかります。性能はほとんど直接の呼び出しと一致します。

    最後に簡単なパッケージを作り、作成したDelegateをキャッシュします。
    
    public class PropertyValue<T>
    {
      private static ConcurrentDictionary<string, MemberGetDelegate> _memberGetDelegate = new ConcurrentDictionary<string, MemberGetDelegate>();
      delegate object MemberGetDelegate(T obj);
      public PropertyValue(T obj)
      {
        Target = obj;
      }
      public T Target { get; private set; }
      public object Get(string name)
      {
        MemberGetDelegate memberGet = _memberGetDelegate.GetOrAdd(name, BuildDelegate);
        return memberGet(Target);
      }
      private MemberGetDelegate BuildDelegate(string name)
      {
        Type type = typeof(T);
        PropertyInfo property = type.GetProperty(name);
        return (MemberGetDelegate)Delegate.CreateDelegate(typeof(MemberGetDelegate), property.GetGetMethod());
      }
    }
    このように使うと便利です。
    
    People people = new People { Name = "Wayne" };
    PropertyValue<People> propertyValue = new PropertyValue<People>(people);
    object value = propertyValue.Get("Name");
    以上はC铉高性能動的に対象属性値を取得するステップの詳細であり、対象属性値をより多く取得するための資料は他の関連記事に注目してください。