Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access a type-safe enumeration of a class's members

Tags:

c#

My class MyClass<t> has the following method

private static bool TypeHasProperty(string NameOfPropertyToMatch)
{
    var properties = typeof(t).GetProperties();
    var requiredProperty = properties.First(
            a => a.Name == NameOfPropertyToMatch);
    if (requiredProperty == null)
    {
        return false
    };

    return true;
}

This is called at the start of a static method:

MyClass<t>.SendToJavaScript(t InstanceOfType, string NameOfPropertyWithinType).

to make sure that InstanceOfType actually has a property of that name before continuing, because otherwise an exception wouldn't get thrown until waaaaay down the line (this information will eventually get serialized and sent to a Javascript Application, which needs to know which property to access in order to do it's job).

I would like for a good, type-safe way to call that method that will not cause the validation to fail if I decide to change the name of my properties later on down the line.

For instance, I do NOT want to call it like this:

MyClass<Person>.SendToJavaScript(MyPerson, "Name")

Because if I decide to change Name to LastName, in the Person class, I would have to make sure to come in and change that magic string.

What I WOULD want, is something like this:

MeClass<Person>.SendToJavaScript(
    MyPerson,
    TypeOf(Person).Properties.Name.ToString())

so that if I use Refactoring to change Name to LastName, the IDE will sweep through there and change my call as well.

Does anything like that exist? Or do I just need to be careful when I refactor? (I love me some F2)

like image 534
JHixson Avatar asked Jan 13 '23 05:01

JHixson


2 Answers

We use something like this in our code:

private static bool TypeHasProperty<P>(Expression<Func<T, P>> accessor)
{
    var propertyName = ((MemberExpression)accessor.Body).Member.Name;
    var properties = typeof(T).GetProperties();
    return properties.Any(a => a.Name == propertyName);
}

Use it:

class Foo
{
    public int Baz { get; set; }
}

MyClass<Foo>.TypeHasProperty(f => f.Baz);

Edit: Changed the query to use Any() as it expresses better what you actually want to do (does a property with the given name exist?)

Note that First() will throw if no match was found.

like image 98
ChrisWue Avatar answered Jan 14 '23 19:01

ChrisWue


Try this:

MeClass<Person>.SendToJavaScript(MyPerson, x => x.Name);

And then:

private static bool TypeHasProperty(Expression propertyExpression)
{
    var expression = GetMemberInfo(propertyExpression);
    string name = expression.Member.Name;

    return typeof(t).GetProperty(name) != null;
}

private static MemberExpression GetMemberInfo(Expression method)
{
    LambdaExpression lambda = method as LambdaExpression;
    if (lambda == null)
        throw new ArgumentNullException("method");

    MemberExpression memberExpr = null;

    if (lambda.Body.NodeType == ExpressionType.Convert)
    {
        memberExpr = 
            ((UnaryExpression)lambda.Body).Operand as MemberExpression;
    }
    else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
    {
        memberExpr = lambda.Body as MemberExpression;
    }

    if (memberExpr == null)
        throw new ArgumentException("method");

    return memberExpr;
}

Taken shamelessly from here: Retrieving Property name from lambda expression

But this is a slightly different question, so I've posted a complete answer.

I've just noticed that in the link I've provided the second answer is much simpler to this. This is covered by ChrisWue'a answer in this thread.

like image 24
BartoszKP Avatar answered Jan 14 '23 19:01

BartoszKP