我想知道是否有更好的方法(比我目前正在做的)只使用对象和属性字符串名来获取并保持对另一个对象中的属性的引用。特别是,使用.Net 4.0的新动态功能有更好的方法吗?
这就是我现在所拥有的。
我有一个“PropertyReference<T>
”对象,它在构造函数中包含对象名称和属性名称。
Initialize()
方法使用反射来查找对象和属性,并将属性Getter存储为Action<T>
,将属性Setter存储为Func<T>
。
当我想要实际调用属性时,我会做这样的事情:
int x = _propertyReference.Get();
或
_propertyReference.Set(2);
这是我的PropertyReference<T>
代码。请剖析并提出改进建议。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
namespace WindowsFormsApplication2
{
public class PropertyReference<T> : IPropertyReference
{
public string ComponentName { get; set; }
public string PropertyName { get; set; }
public bool IsInitialized
{
get
{
return (_action != null && _func != null);
}
}
Action<T> _action;
Func<T> _func;
public PropertyReference() { }
public PropertyReference(string componentName, string propertyName)
{
ComponentName = componentName;
PropertyName = propertyName;
}
public void Initialize(IEntity e)
{
Object component = e.GetByName(ComponentName);
if (component == null) return;
Type t = e.GetByName(ComponentName).GetType();
PropertyInfo pi = t.GetProperty(PropertyName);
_action = (T a) => pi.SetValue(component, a, null);
_func = () => (T)pi.GetValue(component, null);
}
public void Reset()
{
_action = null;
_func = null;
}
public void Set(T value)
{
_action.Invoke(value);
}
public T Get()
{
return _func();
}
}
}
注意:我无法使用“Emit”功能,因为我需要此代码才能在新的Windows Phone 7上运行,并且不支持Emit。
更新
更换后只做了一些速度测试:
_action = (T a) => pi.SetValue(component, a, null);
_func = () => (T)pi.GetValue(component, null);
使用
_action = Action<T>)Delegate.CreateDelegate(typeof(Action<T>),component,pi.GetSetMethod());
_func = (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), component, pi.GetGetMethod());
如下面的dtb所示。
通过对Get()属性进行100,000次调用进行测试。结果如下。
_func = () => (T)pi.GetValue(component, null)
花了大约200毫秒
_func = (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), component, pi.GetGetMethod());
花了大约10毫秒
巨大的差异。没想到,但很酷!
仍有更多改进。
答案 0 :(得分:5)
您可以获得直接表示getter和setter方法的委托:
object component;
PropertyInfo pi;
_action = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>),
component,
pi.GetSetMethod());
_func = (Func<T>)Delegate.CreateDelegate(typeof(Func<T>),
component,
pi.GetGetMethod());
答案 1 :(得分:0)
这实际上取决于你打电话的频率。如果它不是大规模吞吐量,那么很好 - 但请注意,基于反射的GetValue
/ SetValue
非常慢。您可以缓存代理,但另一种简单的方法可能是HyperDescriptor - 它使用与PropertyDescriptor
相同的API(因此您再次获得GetValue
/ SetValue
),但它使用下面的动态方法。然后,API类似于:
PropertyDescriptor prop = TypeDescriptor.GetProperties(type)["PropertyName"];
或
PropertyDescriptor prop = TypeDescriptor.GetProperties(obj)["PropertyName"];
然后
object value = prop.GetValue(component);
prop.SetValue(component, newValue);