gpt4 book ai didi

c# - 性能属性访问和可能的动态编译

转载 作者:行者123 更新时间:2023-11-30 21:17:06 25 4
gpt4 key购买 nike

我有一个解决方案,我需要采用不同的类并按名称访问它的属性

所以如果我有类 HorseCat ,我需要能够通过通用类访问它们,比如 Adapter,比如

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);

}

这本身并不难,stackoverflow 上有很多关于如何做到这一点的线程,您可以使用从反射到动态的一切。然而,就我而言,我需要同时优化性能和内存(不要问为什么 :)

为了避免动态性能损失,我的策略是构建一个适配器接口(interface),比如 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;
}

}

然后每个需要它的类都实现该接口(interface)。问题是如何最好地解决几件事,首先是类型转换。拥有 GetInt、GetString 等可能会更好并且更优化,但看起来你会得到很多你需要以这种方式实现的方法,而且语法并不完全漂亮所以也许更好地接受打击并转换object instead using as 通用索引器可能会很好,但可惜 c# 不支持它们。

另一个问题是 GetValue 和 SetValue 会有多少开销,实现它们的类需要为不同的字段名有一个 switch 或 if-else 分支。尽管我认为如果我使用 OrdinalIgnore 大小写,它不应该增加那么多的开销。也许有更好的解决方案,但我想不出一个,HashTable 似乎更昂贵。恩泰波为了避免手动创建适配器类的繁琐,我认为一个不错的解决方案是生成代码并在运行时动态编译它们(可能使用 CodeDom)。

您怎么看,对于这样的高性能问题,最优雅的解决方案是什么?

基准

我针对大量对象和五个不同的属性测试了四种不同的方法。 “正常”属性访问、“适配器”属性访问、使用反射获取属性以及最后在下面的答案中描述的 Linq 表达式方法

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 表达式的速度是我们讨论的毫秒级的两倍,所以它可能值得使用以避免必须设置适配器。

最佳答案

您可以使用 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);
}
}

这个例子有些简化,因为它只能访问 string 类型的属性,并且不支持 setter。但这应该是一个很好的起点。

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

关于c# - 性能属性访问和可能的动态编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4983920/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com