C# 如何创建委托以读取匿名类型的属性?

C# 如何创建委托以读取匿名类型的属性?,c#,reflection,C#,Reflection,我有一个用匿名类型的实例调用的方法。类型始终相同,但实例不同 注意:我只是作为类型对象传递匿名对象 我知道匿名类型有一个名为Request的属性,类型为HttpRequestMessage。这是我的方法,它是在info.Value中使用匿名类型执行的 void IObserver OnNext(KeyValuePair信息) { HttpRequestMessage请求=????? } 我可以像这样获得属性getter: MethodInfo propertyGetter=type.GetPr

我有一个用匿名类型的实例调用的方法。类型始终相同,但实例不同

注意:我只是作为类型
对象
传递匿名对象

我知道匿名类型有一个名为
Request
的属性,类型为
HttpRequestMessage
。这是我的方法,它是在
info.Value
中使用匿名类型执行的

void IObserver OnNext(KeyValuePair信息)
{
HttpRequestMessage请求=?????
}
我可以像这样获得属性getter:

MethodInfo propertyGetter=type.GetProperty(“请求”).getMethod();
但是,当读取传递给我的实例的属性时,我负担不起反射的成本

如何创建将实例传递给的委托并获取属性值

我试过这个

私有委托HttpRequestMessage RequestPropertyGetterDelegate(对象实例);
私有静态RequestPropertyGetterLegate RequestPropertyGetter;
私有静态RequestPropertyGetterDelegate CreateRequestFromPropertyDelegate(类型)
{
MethodInfo propertyGetter=type.GetProperty(“请求”).getMethod();
return(RequestPropertyGetterDelegate)Delegate.CreateDelegate(typeof(RequestPropertyGetterDelegate),propertyGetter);
}
但是我遇到了一个绑定错误

System.ArgumentException:'无法绑定到目标方法,因为其签名与委托类型的签名不兼容。'


没有Genric ising您正在编写的函数,就无法实现这一点。因为匿名类型比
对象
更具体,所以
对象
参数永远不会绑定

您可以通过将整个内容放在静态泛型类中来解决此问题:

静态类AnonHelper
{
公共只读Func Getter=(Func)
Delegate.CreateDelegate(
类型(Func,propertyGetter)),
类型(T)
.GetProperty(“请求”)
.getMethod()
);
}
您仍然无法访问它,因为无法声明泛型参数

因此,将其包装在外部的函数中(您甚至可以将其作为扩展):

HttpRequestMessage GetProp(T obj)
{
返回anohelper.Getter(obj);
}   
你可以这样称呼它:

GetProp(anonObj)


只有在匿名对象的类型静态已知的点调用
GetProp
时,这才有效,通常与在中声明的方法相同。

使用一些表达式树,它应该是:

private static readonly ConcurrentDictionary<Type, Func<object, string>> extractorsCache = new ConcurrentDictionary<Type, Func<object, string>>();

public static string GetRequest(object obj)
{
    Type type = obj.GetType();

    Func<object, string> extractor = extractorsCache.GetOrAdd(type, BuildExtractor);

    string res = extractor(obj);

    return res;
}

public static Func<object, string> BuildExtractor(Type type)
{
    var par = Expression.Parameter(typeof(object));
    var prop = Expression.Property(Expression.TypeAs(par, type), "Request");
    return Expression.Lambda<Func<object, string>>(prop, par).Compile();
}

请注意,编译后的表达式树缓存在一个
ConcurrentDictionary
中,因此这四个
GetRequest
将生成两个编译后的表达式(因为最后这里有两个匿名类型)。

在这里,使用表达式树。
您所要做的就是缓存
getter
,性能应该与直接访问相同

void Main()
{
    var instance = new TestClass { Request = "Something 2" };
    var getter = CreateRequestFromPropertyDelegate(typeof(TestClass));
    // Cache getter per type
    var value = getter(instance);
    Console.WriteLine(value); // Prints "Something 2"
}

private delegate string RequestPropertyGetterDelegate(object instance);

static RequestPropertyGetterDelegate CreateRequestFromPropertyDelegate(Type type)
{
    // Entry of the delegate
    var instanceParam = Expression.Parameter(typeof(object), "instance");
    
    // Cast the instance from "object" to the correct type
    var instanceExpr = Expression.TypeAs(instanceParam, type);
    
    // Get the property's value
    var property = type.GetProperty("Request");
    var propertyExpr = Expression.Property(instanceExpr, property);
    
    // Create delegate
    var lambda = Expression.Lambda<RequestPropertyGetterDelegate>(propertyExpr, instanceParam);
    return lambda.Compile();
}

class TestClass
{
    // Using string here because I'm on LINQPad
    public string Request { get; set; }
}
void Main()
{
var instance=newtestclass{Request=“Something 2”};
var getter=createRequestFromPropertyLegate(typeof(TestClass));
//每种类型的缓存getter
var值=getter(实例);
Console.WriteLine(值);//打印“某物2”
}
私有委托字符串RequestPropertyGetterDelegate(对象实例);
静态RequestPropertyGetterDelegate CreateRequestFromPropertyDelegate(类型)
{
//代表的发言
var instanceParam=Expression.Parameter(typeof(object),“instance”);
//将实例从“对象”强制转换为正确的类型
var instanceExpr=Expression.TypeAs(instanceParam,type);
//获取属性的值
var property=type.GetProperty(“请求”);
var propertyExpr=Expression.Property(instanceExpr,Property);
//创建委托
var lambda=Expression.lambda(propertyExpr,instanceParam);
返回lambda.Compile();
}
类TestClass
{
//在这里使用字符串,因为我在LINQPad上
公共字符串请求{get;set;}
}

您“负担不起反射的成本”,但您继续创建一段同时使用反射和委托的代码?如果类型相同,为什么不缓存MethodInfo呢?
params
在此实例中没有意义,而且
对象实例
参数无论如何都会失败。如果从MethodInfo创建委托,则它不会使用反射。因此,您可以反射一次以找到MethodInfo,然后从那里开始避免反射。您不能,因为类型未知。这里有一个解决方法,postExpression树会在这里完成这项工作,并且会有很多性能。anonObj将始终是
对象类型
-因此这对我没有帮助,是吗?取决于您是否仍在使用
var
声明它的位置,您仍然可以访问该类型否,该对象被传递为(更新了问题)。那么这显然是不可能的。你不能在没有反射的情况下访问你的缓存
void Main()
{
    var instance = new TestClass { Request = "Something 2" };
    var getter = CreateRequestFromPropertyDelegate(typeof(TestClass));
    // Cache getter per type
    var value = getter(instance);
    Console.WriteLine(value); // Prints "Something 2"
}

private delegate string RequestPropertyGetterDelegate(object instance);

static RequestPropertyGetterDelegate CreateRequestFromPropertyDelegate(Type type)
{
    // Entry of the delegate
    var instanceParam = Expression.Parameter(typeof(object), "instance");
    
    // Cast the instance from "object" to the correct type
    var instanceExpr = Expression.TypeAs(instanceParam, type);
    
    // Get the property's value
    var property = type.GetProperty("Request");
    var propertyExpr = Expression.Property(instanceExpr, property);
    
    // Create delegate
    var lambda = Expression.Lambda<RequestPropertyGetterDelegate>(propertyExpr, instanceParam);
    return lambda.Compile();
}

class TestClass
{
    // Using string here because I'm on LINQPad
    public string Request { get; set; }
}