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; }
}