Как получить свойство от анонимного типа, используя Expression.Parameter? - PullRequest
0 голосов
/ 24 сентября 2018

Я пытаюсь сгенерировать динамическую лямбду, используя анонимный класс, однако у меня возникает проблема, когда я пытаюсь связать свойство с моей моделью в анонимном классе.

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'

Как я могу решить эту проблему?

1 Ответ

0 голосов
/ 25 сентября 2018

Я использую некоторые методы расширения для расширения 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));
    }
}
...