Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a property in via a lambda expression?

Tags:

c#

lambda

There are some unit tests on my project where we want to be able to set some properties that have private setters. Currently I'm doing it via reflection and this extension method:

public static void SetPrivateProperty(this object sourceObject, string propertyName, object propertyValue)
{
    sourceObject.GetType().GetProperty(propertyName).SetValue(sourceObject, propertyValue, null);
}

Assuming I had a TestObject like this:

public class TestObject
{
    public int TestProperty{ get; private set; }
}

I can then call this in my unit tests as follows:

myTestObject.SetPrivateProperty("TestProperty", 1);

However, I'd like to have validation of the property name at compile time, and thus I'd like to be able to pass the property in via expression, like this:

myTestObject.SetPrivateProperty(o => o.TestProperty, 1);

How can I do this?

like image 796
Sterno Avatar asked Apr 17 '12 14:04

Sterno


2 Answers

If the getter is public, then the following should work. It will give you an extension method that looks like this:

var propertyName = myTestObject.NameOf(o => o.TestProperty);

It requires a public getter. I hope, at some point, reflection functionality like this is rolled into the language.

public static class Name
{
    public static string Of(LambdaExpression selector)
    {
        if (selector == null) throw new ArgumentNullException("selector");

        var mexp = selector.Body as MemberExpression;
        if (mexp == null)
        {
            var uexp = (selector.Body as UnaryExpression);
            if (uexp == null)
                throw new TargetException(
                    "Cannot determine the name of a member using an expression because the expression provided cannot be converted to a '" +
                    typeof(UnaryExpression).Name + "'."
                );
            mexp = uexp.Operand as MemberExpression;
        }

        if (mexp == null) throw new TargetException(
            "Cannot determine the name of a member using an expression because the expression provided cannot be converted to a '" +
            typeof(MemberExpression).Name + "'."
        );
        return mexp.Member.Name;
    }

    public static string Of<TSource>(Expression<Func<TSource, object>> selector)
    {
        return Of<TSource, object>(selector);
    }

    public static string Of<TSource, TResult>(Expression<Func<TSource, TResult>> selector)
    {
        return Of(selector as LambdaExpression);
    }
}

public static class NameExtensions
{
    public static string NameOf<TSource, TResult>(this TSource obj, Expression<Func<TSource, TResult>> selector)
    {
        return Name.Of(selector);
    }
}
like image 183
ken Avatar answered Sep 18 '22 17:09

ken


New to C# 6.0 : nameof(property)

like image 36
Bryan Avatar answered Sep 19 '22 17:09

Bryan