2011-02-13 87 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實例。然後爲每個訪問的屬性名稱緩存一個編譯的表達式。