通过反射将访问器 Func 加载到 Dictionary 中

Load accessor Func by reflection into Dictionary

背景:用户应该能够尽可能高效合理地选择一个DB-Table/Model/Class和filter/sort/display它的所有public属性。

名称可以通过反射查询-API,但我想知道,是否可以通过这种方式存储这些访问并提高效率?

这个例子展示了它是如何完成的,但是在每次访问时它都会查询函数中的反射-api。

public class TestClass // the Model or Table
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public static void Main( string[] args )
{
    var testClasses = new TestClass[] {
        new TestClass { Id = 1 , Name = "1" } ,
        new TestClass { Id = 2 , Name = "2" } ,
        new TestClass { Id = 3 , Name = "3" } ,
    };

    var propertyInfos = typeof( TestClass ).GetProperties();
    var map = new Dictionary<string,Func<object,object>>(); // Func<object,object> -> Func takes an instance of the class and return a public property

    // load the map once
    foreach( var propertyInfo in propertyInfos )
    {
        Func<object,object> func = x => propertyInfo.GetValue( x );

        map.Add( propertyInfo.Name , func );
    }

    // get the names by user-input
    var names = propertyInfos.Select( x => x.Name ).ToArray();

    // load the properties by name
    foreach( var testClass in testClasses )
    {
        Console.WriteLine( $"{testClass.Id} - {testClass.Name}" );

        foreach( var name in names )
        {
            var func = map[ name ];
            var value = func( testClass ); // this is 'bad' as it uses reflection every invokation

            Console.WriteLine( $"\t{name} = {value}" );
        }
    }
}

我的问题是:这本词典可以吗

var map = new Dictionary<string,Func<object,object>> {
    { "Id"      , x => ( x as TestClass ).Id    } ,
    { "Name"    , x => ( x as TestClass ).Name  } ,
};

通过提供类型自动创建(并且不在每次调用时使用反射)?

您可以通过从每次调用中删除反射并只执行一次来获得一些东西:

var par = Expression.Parameter(typeof(object), "row");

// load the map once
foreach (var propertyInfo in propertyInfos)
{
    Func<object, object> func = Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Property(Expression.Convert(par, propertyInfo.DeclaringType), propertyInfo), typeof(object)), par).Compile();
    map.Add(propertyInfo.Name, func);
}

我创建了一个 vary small 表达式树,将参数对象转换为 "correct" 类型(在本例中为 TestClass),调用 getter 的 属性并将结果转换为 object.