这是一个相当基本的解决方案,针对每种类型简单地缓存Getters/Setters。
public static class CachedPropertyAccessUtilsFactory
{
public static CachedPropertyAccessUtils<TWrapped> Create<TWrapped>(
TWrapped instance)
{
return new CachedPropertyAccessUtils<TWrapped>(instance);
}
}
public class CachedPropertyAccessUtils<TWrapped>
{
private readonly TWrapped _instance;
public CachedPropertyAccessUtils(TWrapped instance)
{
_instance = instance;
}
public GetSetWrapper<TProperty> Property<TProperty>(string propertyName)
{
return new GetSetWrapper<TProperty>(_instance, propertyName);
}
public class GetSetWrapper<TProperty>
{
private static readonly ConcurrentDictionary<string, GetterAndSetterTuple> GettersAndSettersByPropertyName
= new ConcurrentDictionary<string, GetterAndSetterTuple>();
private readonly TWrapped _instance;
private readonly string _propertyName;
public GetSetWrapper(TWrapped instance, string propertyName)
{
_instance = instance;
_propertyName = propertyName;
GettersAndSettersByPropertyName.GetOrAdd(propertyName, _ => new GetterAndSetterTuple() {
Getter = (Func<TWrapped, TProperty>)Delegate
.CreateDelegate(typeof(Func<TWrapped, TProperty>),
null,
typeof(TWrapped)
.GetProperty(propertyName)
.GetGetMethod()),
Setter = (Action<TWrapped, TProperty>)Delegate
.CreateDelegate(typeof(Action<TWrapped, TProperty>),
null,
typeof(TWrapped)
.GetProperty(propertyName)
.GetSetMethod())
});
}
public TProperty GetValue()
{
return GettersAndSettersByPropertyName[_propertyName].Getter(_instance);
}
public GetSetWrapper<TProperty> SetValue(TProperty value)
{
GettersAndSettersByPropertyName[_propertyName].Setter(_instance, value);
return this;
}
class GetterAndSetterTuple
{
public Func <TWrapped, TProperty> Getter { get; set; }
public Action<TWrapped, TProperty> Setter { get; set; }
}
}
}
用法示例:
var myInstance = SomeCodeToCreateATypeAtRuntimeAndCreateAnInstanceOfIt();
var wrappedInstance = CachedPropertyAccessUtilsFactory.Create(myInstance);
wrappedInstance.Property<int>("Property1").SetValue(99);
wrappedInstance.Property<int>("Property1").GetValue();
var property1 = wrappedInstance.Property<int>("Property1");
property1.SetValue(-1);
property1.GetValue();
当然,这假设您在运行时知道属性类型,以便可以切换到正确的Property<TProperty>()
调用。
如果您没有这些信息,则可以添加另一层间接层,通过反射将string propertyName
映射到包装类型上的相应属性,并缓存查找结果。
在这种情况下,返回的GetSetWrapper
当然必须支持带有object
作为返回/参数类型的GetValue
/SetValue
,这将涉及幕后一些强制转换/装箱操作。
object
或dynamic
吗? - vzwick