gpt4 book ai didi

c# - 通过反射同时设置多个属性

转载 作者:行者123 更新时间:2023-11-30 15:10:33 25 4
gpt4 key购买 nike

我正在尝试优化代码中的反射利用率,我想知道是否可以一次设置对象的多个属性:

示例用法:

private void SetProperties<T>(List<T> objects, List<Tuple<string, object>> propsAndValues) where T:Task
{
Type type = typeof(T);
var propInfos = propsAndValues.ToDictionary(key => type.GetProperty(key.Item1, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.SetProperty), elem => elem.Item2);

objects.AsParallel().ForAll(obj =>
{
obj.SetProps(propInfos);
});

}

在哪里

public static void SetProps<T>(this T obj, Dictionary<PropertyInfo, object> propInfos) where T : Task
{
foreach (var propInfo in propInfos)
{
propInfo.Key.SetValue(obj, propInfo.Value, null);
}
}

我想用更高效的方法替换 SetProps 扩展方法,但还没有找到合适的方法。提前致谢;)

我已经使用评论中提供的链接修改了代码。常规方式仍然快 4 倍。问题是这是极限还是有改进的空间?

class DelegateFactory
{
public delegate void LateBoundPropertySet(object target, object value);

public delegate void LateBoundPropertyListSet(object target, List<object> values);

public static LateBoundPropertySet CreateSetIL(PropertyInfo property)
{
var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(object), typeof(object) }, true);
var gen = method.GetILGenerator();

var sourceType = property.DeclaringType;
var setter = property.GetSetMethod(true);

gen.Emit(OpCodes.Ldarg_0); // Load input to stack
gen.Emit(OpCodes.Castclass, sourceType); // Cast to source type
gen.Emit(OpCodes.Ldarg_1); // Load value to stack
gen.Emit(OpCodes.Unbox_Any, property.PropertyType); // Unbox the value to its proper value type
gen.Emit(OpCodes.Callvirt, setter); // Call the setter method
gen.Emit(OpCodes.Ret);

var result = (LateBoundPropertySet)method.CreateDelegate(typeof(LateBoundPropertySet));

return result;
}

public static LateBoundPropertySet CreateSet(PropertyInfo property)
{

var setterType = typeof(Action<,>).MakeGenericType(property.DeclaringType, property.PropertyType);

var propertyWriter = typeof(PropertyWriter<,>).MakeGenericType(property.DeclaringType, property.PropertyType);

var setterDelegate = Delegate.CreateDelegate(setterType, property.GetSetMethod());

var writer = (IPropertyWriter)Activator.CreateInstance(propertyWriter, setterDelegate);

return writer.SetValue;

}

private interface IPropertyWriter
{
void SetValue(object instance, object value);
}

private interface IPropertyListWriter
{

void SetValues(object instance, List<object> values);

}

private class PropertyWriter<TInstance, TProperty> : IPropertyWriter
{

private readonly Action<TInstance, TProperty> _setValueDelegate;

public PropertyWriter(Action<TInstance, TProperty> setValueDelegate)
{

_setValueDelegate = setValueDelegate;

}

public void SetValue(object instance, object value)
{

_setValueDelegate((TInstance)instance, (TProperty)value);
}

}

}

public static void SetProps2<T>(this T obj, Dictionary<DelegateFactory.LateBoundPropertySet, object> propSetters) where T : Task
{
foreach (var propSet in propSetters)
{
propSet.Key.Invoke(propSet, propSet.Value);
}
}

最佳答案

如果您进行了充分的反射(reflection),认为这是真正的瓶颈,那么动态代码可能值得研究。在那之前-也许HyperDescriptor会降低成本;非常相似的代码,但便宜得多。

在 .NET 4.0 及更高版本中,Expression API 允许您设置多个属性,但这只有在缓存委托(delegate)时才真正可行。另一个有趣的选项(具有相同的约束:您必须缓存并重新使用委托(delegate))是 DynamicMethod。但是,所有这些选项都是相当高级的主题。我很乐意提供建议,但您真的需要这个吗?

关于c# - 通过反射同时设置多个属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3218660/

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