我正在尝试使用匿名类生成动态lambda,但是当我尝试在匿名类中获取与模型相关的属性时,我遇到了问题。
public class Program
{
public class Model
{
public string Folder { get; set; }
}
public static void Main()
{
Select<Model>(new string[] { "Folder" });
}
public static void Select<TResult>(string[] propertyNames)
{
var anonymousType = CreateAnonymousType(propertyNames);
var parameter = Expression.Parameter(anonymousType, "item");
foreach (var prop in parameter.GetType().GetProperties())
Console.WriteLine(prop);
var bindings = propertyNames
.Select(name => name.Trim())
.Select(name => Expression.Bind(
typeof(TResult).GetProperty(name),
Expression.Property(parameter, name) // here I have the issue, when the method try to find the property "Folder" in the anonymou type, throw an exception.
));
var newT = Expression.MemberInit(Expression.New(typeof(TResult)), bindings);
var lambda = Expression.Lambda<Func<Type, TResult>>(newT, parameter);
Console.WriteLine(lambda.ToString());
}
public static Type CreateAnonymousType(string[] properties)
{
AssemblyName dynamicAssemblyName = new AssemblyName("TempAssembly");
AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("TempAssembly");
TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("AnonymousType", TypeAttributes.Public);
foreach (var property in properties)
dynamicAnonymousType.DefineField(property, typeof(object), FieldAttributes.Public);
return dynamicAnonymousType.CreateType();
}
}
当我执行代码时:Expression.Property(parameter, name)
抛出此异常:
运行时异常(第23行):实例属性“文件夹”不是 为类型'System.RuntimeType'定义的
如何解决此问题?
答案 0 :(得分:0)
我使用一些扩展方法来扩展MemberInfo
,以便您可以以统一的方式处理属性或字段:
// ***
// *** Type Extensions
// ***
public static List<MemberInfo> GetPropertiesOrFields(this Type t, BindingFlags bf = BindingFlags.Public | BindingFlags.Instance) =>
t.GetMembers(bf).Where(mi => mi.MemberType == MemberTypes.Field | mi.MemberType == MemberTypes.Property).ToList();
// ***
// *** MemberInfo Extensions
// ***
public static object GetValue(this MemberInfo member, object srcObject) {
switch (member) {
case FieldInfo mfi:
return mfi.GetValue(srcObject);
case PropertyInfo mpi:
return mpi.GetValue(srcObject);
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo or PropertyInfo", nameof(member));
}
}
public static T GetValue<T>(this MemberInfo member, object srcObject) => (T)member.GetValue(srcObject);
public static void SetValue<T>(this MemberInfo member, object destObject, T value) {
switch (member) {
case FieldInfo mfi:
mfi.SetValue(destObject, value);
break;
case PropertyInfo mpi:
mpi.SetValue(destObject, value);
break;
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo or PropertyInfo", nameof(member));
}
}
public static Type GetMemberType(this MemberInfo member) {
switch (member) {
case FieldInfo mfi:
return mfi.FieldType;
case PropertyInfo mpi:
return mpi.PropertyType;
case EventInfo mei:
return mei.EventHandlerType;
default:
throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", nameof(member));
}
}
public static bool GetCanWrite(this MemberInfo member) {
switch (member) {
case FieldInfo mfi:
return true;
case PropertyInfo mpi:
return mpi.CanWrite;
default:
throw new ArgumentException("MemberInfo must be if type FieldInfo or PropertyInfo", nameof(member));
}
}