2011-02-13 69 views
2

我有一个解决方案,我需要采取不同的类和访问它的名字的属性高性能属性访问和可能的动态编译

,所以如果我有实例的类,我需要能够通过一个通用类来访问他们,说适配器,像

HorseAdapter adapter = new HorseAdapter(); 

public SomeMethod() 
{ 
    Horse horse = new Horse(); 
    DoStuff(horse, adapter); 
} 

public DoStuff(object obj, IAdapter adapter) 
{ 
    int speed = (int)adapter.GetValue(obj,"speed"); 
    string name = adapter.GetValue(obj,"name") as string; 
    adapter.SetValue(obj,"gender",true); 

} 

这并不困难本身并有计算器的线程上如何做到这一点,你可以用一切从反射动态主机。然而,在我来说,我需要优化性能和内存(不要问为什么:)

为了解决动态性能惩罚我的策略是要建立一个适配器接口,说IADAPTER,它实现

object GetValue(object obj,string fieldName) 
SetValue(object obj,string fieldName,object value) 

所以

public class HorseAdapter : IAdapter 
{ 
.. 

public override GetValue(object obj, string fieldName) 
{ 
    Horse horse = object as Horse, 
    if (fieldName == "name") 
     return horse.Name; 
    else if (fieldName == "speed") 
    return horse.Speed; 
} 

} 

然后,每个需要它的类实现该接口。问题是如何最好地解决一些事情,第一种类型转换。这可能是更好,更优化有GetInt,GetString等等,但似乎你会得到很多方法,你需要以这种方式实现,语法并不完美,所以也许更好地采取命中和施放对象,而不是使用一个通用的索引或许会一直不错,但可惜C#不支持他们。

另一个问题是的GetValue和的SetValue多少开销都会有,实现他们的类需要有一个开关或的if-else分支为不同的字段名。尽管我认为如果使用OrdinalIgnore的话,它应该不会增加太多的开销。也许有更好的解决方案,但我想不出一个,HashTable似乎更昂贵。 ntepo 为了避免手动创建适配器类我的想法是一个很好的解决办法是将生成的代码和编译它们动态运行时(可能使用的CodeDOM)的沉闷。

你怎么想,什么是与高性能这样的问题,最好的解决方法?

基准

我测试了大量的对象的四种不同方法和五个不同的性质。 “正常”属性访问“适配器”属性访问,使用反射,最后在答案下面

elapsed time normal properties:468 ms 
elapsed time reflection properties:4657 ms 
elapsed time adapter properties:551 ms 
elapsed time expression properties:1041 ms 

描述的LINQ表达式方法获取属性好像使用适配器是稍微慢然后直行属性,LINQ表达式是大约是慢两倍,反射速度是慢十倍。

即使LINQ表达式是慢一倍它是我们谈论所以它可能是值得使用,以避免设置适配器毫秒。

+0

您可以使用泛型:`GetValue `等 – Vlad 2011-02-13 11:58:37

+0

为什么不能让Horse/Cat类实现相同的`interface IAnimal {string Name {get; set;} int Speed {get; set;} }`?这可能会带来最好的表现。 – Vlad 2011-02-13 12:03:38

回答

4

您可以使用LinqExpression类:

public class PropertyAccessor 
{ 
    Dictionary<string, Func<object, string>> _accessors = new Dictionary<string,Func<object,string>>(); 
    Type _type; 

    public PropertyAccessor(Type t) 
    { 
     _type = t; 
    } 


    public string GetProperty(object obj, string propertyName) 
    { 
     Func<object, string> accessor; 

     if (!_accessors.ContainsKey(propertyName)) 
     { 
      ParameterExpression objExpr = Expression.Parameter(typeof(object), "obj"); 
      Expression e = Expression.Convert(objExpr, _type); 
      e = Expression.Property(e, propertyName); 
      Expression<Func<object, string>> expr = Expression.Lambda<Func<object, string>>(e, objExpr); 
      accessor = expr.Compile(); 
      _accessors[propertyName] = accessor; 
     } 
     else 
     { 
      accessor = _accessors[propertyName]; 
     } 

     return accessor(obj); 
    } 
} 

这个例子有些简化,因为它能够型的,只有访问属性它支持没有setter方法。但它应该是一个很好的起点。

对于在运行时遇到的每种类型,必须创建一个PropertyAccessor实例。然后为每个访问的属性名称缓存一个编译的表达式。