为属性setter或getter创建一个高性能的开放委托
开放委托是没有目标的实例方法的委托。 要调用它,您需要提供目标作为其第一个参数。 它们是优化代码的一种聪明方法,否则会使用reflection并且性能较差。 有关开放代表的介绍,请参阅此内容 。 你在实践中使用它的方法是使用昂贵的reflection代码来构建这些开放的委托,但是你可以像一个简单的委托调用那样非常便宜地调用它们。
我正在尝试编写将任意PropertyInfo转换为其setter的委托的代码。 到目前为止,我想出了这个:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace Test { class TestClass { static Action MakeSetterDelegate(PropertyInfo property) { MethodInfo setMethod = property.GetSetMethod(); if (setMethod != null && setMethod.GetParameters().Length == 1) //skips over nasty index properties { //To be able to bind to the delegate we have to create a delegate //type like: Action rather than Action. //We use reflection to do that Type setterGenericType = typeof(Action); Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType }); var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod); //we wrap the Action delegate into an Action Action setter = (instance, value) => { untypedDelegate.DynamicInvoke(new object[] { instance, value }); }; return setter; } else { return null; } } int TestProp { set { System.Diagnostics.Debug.WriteLine("Called set_TestProp"); } } static void Test() { PropertyInfo property = typeof(TestClass).GetProperty("TestProp"); Action setter = MakeSetterDelegate(property); TestClass instance = new TestClass(); setter(instance, 5); } } }
将为getter编写类似的代码。 它可以工作,但是setter委托使用DynamicInvoke从Action <derivedType
>转换为Action <object
>,我怀疑它正在吃掉我所追求的优化的很大一部分。 所以问题是:
- DynamicInvoke真的是一个真正的问题吗?
- 不管怎么说呢?
DynamicInvoke
不会创建一个高性能的setter。 反对generics内部类型的reflection在这里是更好的选择,因为这将允许您使用类型化的委托。 另一个选项是DynamicMethod
,但是你需要担心一些IL细节。
您可能希望查看HyperDescriptor
,它将IL工作包装到PropertyDescriptor
实现中。 另一个选项是Expression
API(如果您使用的是.NET 3.5或更高版本):
static Action MakeSetterDelegate(PropertyInfo property) { MethodInfo setMethod = property.GetSetMethod(); if (setMethod != null && setMethod.GetParameters().Length == 1) { var target = Expression.Parameter(typeof(T)); var value = Expression.Parameter(typeof(object)); var body = Expression.Call(target, setMethod, Expression.Convert(value, property.PropertyType)); return Expression.Lambda>(body, target, value) .Compile(); } else { return null; } }
或者使用通用类型:
abstract class Setter { public abstract void Set(T obj, object value); } class Setter : Setter { private readonly Action del; public Setter(MethodInfo method) { del = (Action) Delegate.CreateDelegate(typeof(Action), method); } public override void Set(TTarget obj, object value) { del(obj, (TValue)value); } } static Action MakeSetterDelegate(PropertyInfo property) { MethodInfo setMethod = property.GetSetMethod(); if (setMethod != null && setMethod.GetParameters().Length == 1) { Setter untyped = (Setter ) Activator.CreateInstance( typeof(Setter<,>).MakeGenericType(typeof(T), property.PropertyType), setMethod); return untyped.Set; } else { return null; } }
我曾经上过这堂课。 也许它有帮助:
public class GetterSetter { private readonly Func getter; private readonly Action setter; private readonly string propertyName; private readonly Expression> propertyNameExpression; public EntityType Entity { get; set; } public GetterSetter(EntityType entity, Expression> property_NameExpression) { Entity = entity; propertyName = GetPropertyName(property_NameExpression); propertyNameExpression = property_NameExpression; //Create Getter getter = propertyNameExpression.Compile(); // Create Setter() MethodInfo method = typeof (EntityType).GetProperty(propertyName).GetSetMethod(); setter = (Action) Delegate.CreateDelegate(typeof(Action), method); } public propType Value { get { return getter(Entity); } set { setter(Entity, value); } } protected string GetPropertyName(LambdaExpression _propertyNameExpression) { var lambda = _propertyNameExpression as LambdaExpression; MemberExpression memberExpression; if (lambda.Body is UnaryExpression) { var unaryExpression = lambda.Body as UnaryExpression; memberExpression = unaryExpression.Operand as MemberExpression; } else { memberExpression = lambda.Body as MemberExpression; } var propertyInfo = memberExpression.Member as PropertyInfo; return propertyInfo.Name; }
测试:
var gs = new GetterSetter(new OnOffElement(), item => item.IsOn); gs.Value = true; var result = gs.Value;
- c #datagridview红叉
- FormsViewGroup.dll(v7.1)的$(TargetFrameworkVersion)大于项目的$(TargetFrameworkVersion)(v6.0)xamarin
- ServiceStack – validation和数据库访问
- 由非托管应用程序托管的托管组件中的Await和SynchronizationContext
- entity framework4和同义词
- 是否有可能让Entity Framework识别已创建但尚未保存在数据库中的对象?
- .net新进程沙箱,用于不受信任的代码
- 在一个页面上显示两个网页
- 如何通过指定发件人地址使用Microsoft.Office.Interop.Outlook.MailItem发送邮件