Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
340 views
in Technique[技术] by (71.8m points)

c# - How can I create a delegate to read a property of an anonymous type?

I have a method that is called with an instance of an anonymous type. The type is always the same, but the instance is different.

NOTE: I am passed the anonymous object simply as a type object.

I know the anonymous type has a property named Request of type HttpRequestMessage. Here is my method that is executed with the anonymous type in info.Value.

void IObserver<KeyValuePair<string, object> event> OnNext(KeyValuePair<string, object> info)
{
  HttpRequestMessage request = ?????
}

I can get the property getter like so:

MethodInfo propertyGetter = type.GetProperty("Request").GetGetMethod();

But I can't afford the cost of reflection when reading the property of the instance passed to me.

How can I create a delegate that I pass the instance to and get the property value?

I tried this

private delegate HttpRequestMessage RequestPropertyGetterDelegate(object instance);
private static RequestPropertyGetterDelegate RequestPropertyGetter;

private static RequestPropertyGetterDelegate CreateRequestFromPropertyDelegate(Type type)
{
    MethodInfo propertyGetter = type.GetProperty("Request").GetGetMethod();
    return (RequestPropertyGetterDelegate)Delegate.CreateDelegate(typeof(RequestPropertyGetterDelegate), propertyGetter);
}

But I am experiencing a binding error

System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Here it is, using expression trees.
All you have to do is cache the getter, the performance should be the same as direct access.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...