gpt4 book ai didi

c# - 如何创建可以处理或转换未知类型的 lambda 表达式?

转载 作者:行者123 更新时间:2023-11-30 14:15:13 26 4
gpt4 key购买 nike

如何为可以处理未知类型的函数创建 lambda 表达式?抱歉,我知道这个问题含糊不清,我很难形成它。我只希望你有时间读一读我的故事,这应该会让事情变得清晰一些。

我的目标是使用预定义的数据协定将字符串值数组反序列化为一个对象。数据合约的成员有一个职位编号。反序列化器的简单工作是将值映射到数据成员(在进行适当的类型转换之后),然后构建对象。

问题是反序列化性能很差!运行 VS Profiler 后,我发现用于填充对象成员的 PropertyInfo.SetValue() 花费的时间最多。我的程序必须在任何给定时间反序列化数千个对象。数据合约通常有 100 个成员。所以我们说的是每 1000 个对象对 SetValue() 调用 100,000 次,而且它在拖延。下面是调用 SetValue 的示例:

// for each data contract type
// go through each property and set the value
foreach(PropertyInfo pi in pis)
{
object data = convertStringToMemberType(pi, attributeArray, valueStringArray);
pi.SetValue(objectToBuild, data, null);
}

然后我找到this page from Unknown Recipes ,它对这个性能问题有一个有前途的解决方案。看起来我需要使用已编译的 lambda 表达式来替换 SetValue,但我遇到了转换问题。按照上面链接中的示例,我现在有了 SetValue() 的替代品。替代品是 Action 委托(delegate),它们是已编译的 lambda 表达式。

首先,我扩展了 PropertyInfo 类。

public static class PropertyInfoExtensions
{

public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo)
{
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
var argument = Expression.Parameter(typeof(object), "a");
var setterCall = Expression.Call(
instance,
propertyInfo.GetSetMethod(),
Expression.Convert(argument, propertyInfo.PropertyType));
return (Action<object, object>)Expression.Lambda(setterCall, instance, argument).Compile();
}
}

然后我建了一个Dictionary<PropertyInfo, Action<object, object>对象,它将每个 propertyInfo 对象绑定(bind)到其相应的 Action 委托(delegate)。这样我就可以“缓存”已编译的 lambda 并在一批反序列化中重用它。这就是我现在的称呼:

foreach(PropertyInfo pi in pis)
{
object data = convertStringToMemberType(pi, attributeArray, valueStringArray);
var setValueDelegate = _actionDelegateDict[pi];
setValueDelegate(objectToBuild, data);
}

但是,我收到以下异常:

Unable to cast object of type 'System.Action`2[Test.DataContract1,System.Object]' to type 'System.Action`2[System.Object,System.Object]'.

这里的 DataContract1 是我要构建的对象的类型。它仅在运行时已知,这与 Unknown Recipes 示例中的场景不同,后者的类型在编译时已知。你将如何使这个 lambda 表达式起作用?

非常感谢您的宝贵时间!

最佳答案

听起来很像我对 FastReflection 所做的图书馆。您几乎在那里,您只需将实例参数更改为对象类型,然后将该表达式转换为实际类型。

我认为如果将您现在拥有的代码更改为此代码,则可以正常工作。

public static class PropertyInfoExtensions
{
public static Action<object, object> GetValueSetter(this PropertyInfo propertyInfo)
{
var instance = Expression.Parameter(typeof(object), "i");
var argument = Expression.Parameter(typeof(object), "a");
var setterCall = Expression.Call(
Expression.Convert(instance, propertyInfo.DeclaringType),
propertyInfo.GetSetMethod(),
Expression.Convert(argument, propertyInfo.PropertyType));
return Expression.Lambda<Action<object,object>>(setterCall, instance, argument).Compile();
}
}

关于c# - 如何创建可以处理或转换未知类型的 lambda 表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10423221/

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