How can I pass a property as a delegate?

前端 未结 6 1538
深忆病人
深忆病人 2021-02-04 04:03

This is a theoretical question, I\'ve already got a solution to my problem that took me down a different path, but I think the question is still potentially interesting.

6条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-04 04:58

    Ignoring whether this is useful in your specific circumstances (where I think the approach you've taken works just fine), your question is 'is there a way to convert a property into a delegate'.

    Well, there kind of might be.

    Every property actually (behind the scenes) consists of one or two methods - a set method and/or a get method. And you can - if you can get a hold of those methods - make delegates that wrap them.

    For instance, once you've got hold of a System.Reflection.PropertyInfo object representing a property of type TProp on an object of type TObj, we can create an Action (that is, a delegate that takes an object on which to set the property and a value to set it to) that wraps that setter method as follows:

    Delegate.CreateDelegate(typeof (Action), propertyInfo.GetSetMethod())
    

    Or we can create an Action that wraps the setter on a specific instance of TObj like this:

    Delegate.CreateDelegate(typeof (Action), instance, propertyInfo.GetSetMethod())
    

    We can wrap that little lot up using a static reflection extension method:

    public static Action GetPropertySetter(this TObject instance, Expression> propAccessExpression)
    {
        var memberExpression = propAccessExpression.Body as MemberExpression;
        if (memberExpression == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
    
        var accessedMember = memberExpression.Member as PropertyInfo;
        if (accessedMember == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
    
        var setter = accessedMember.GetSetMethod();
    
        return (Action) Delegate.CreateDelegate(typeof(Action), instance, setter);
    }
    

    and now I can get a hold of a 'setter' delegate for a property on an object like this:

    MyClass myObject = new MyClass();
    Action setter = myObject.GetPropertySetter(o => o.Property1);
    

    That's strongly typed, based on the type of the property itself, so it's robust in the face of refactoring and compile-time typechecked.

    Of course, in your case, you want to be able to set your property using a possibly-null object, so a strongly typed wrapper around the setter isn't the whole solution - but it does give you something to pass to your SetPropertyFromDbValue method.

提交回复
热议问题