我正在使用此.Net反射代码在运行时生成动态类实例。
https://www.c-sharpcorner.com/UploadFile/87b416/dynamically-create-a-class-at-runtime/
我正在使用.Net反射来创建具有动态属性集的对象列表,因为我从excel文件读取了输入,根据业务需求,该文件可能具有动态列。但是我正在做很多循环来获取GetType().GetProperty("")
,这会降低性能。我试图为从PropertiesInfo[]
获得的GetType().GetProperties()
动态地委派它。
下面是所创建的运行时类的Property1的静态getter和setter委托。
Action<MyClass, int> setter = (Action<MyClass, int>)Delegate.CreateDelegate(typeof(Action<MyClass, int>), null, typeof(MyClass).GetProperty("Property1").GetSetMethod());
Func<MyClass, int> getter = (Func<MyClass, int>)Delegate.CreateDelegate(typeof(Func<MyClass, int>), null, typeof(MyClass).GetProperty("Property1").GetGetMethod());
我想为我的课程创建的每个属性动态化。我很困惑,不确定是否可以使用任何Linq MemberExpression
来实现它。
有人可以帮我吗?那太好了。
答案 0 :(得分:2)
这是解决您的问题的基本方法,只需缓存每种类型的Getters / Setters。
public static class CachedPropertyAccessUtilsFactory
{
/*
* Convenience Factory to avoid creating instances of
* CachedPropertyAccessUtils by reflection
*/
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>
{
/*
* Caches generated getters/setters by property name.
* Since this field is static it is shared between all instances with
* identical TWrapped and 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;
// Create a Getter/Setter pair if none has been generated previously
GettersAndSettersByPropertyName.GetOrAdd(propertyName, (ignored) => 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);
// The first call to Property() will generate the corresponding Getter/Setter
wrappedInstance.Property<int>("Property1").SetValue(99);
// Subsequent calls will use the cached Getter/Setter
wrappedInstance.Property<int>("Property1").GetValue(); // => 99
// The property can be conveniently held on to:
var property1 = wrappedInstance.Property<int>("Property1");
property1.SetValue(-1);
property1.GetValue(); // => -1
所有这些当然都假定您在运行时知道属性类型,因此您可以switch
进入正确的Property<TProperty>()
调用。
如果您没有此信息,则可以添加另一层间接寻址,通过反射并缓存查找结果将string propertyName
映射到包装类型上的相应属性。
在这种情况下,返回的GetSetWrapper
当然必须支持GetValue
的{{1}} / SetValue
作为返回/参数类型,这将涉及一些强制转换/装箱在幕后来回