views:

205

answers:

2

Hi,

I think the title says it all. I want a static helper method to remove magic strings. Of course, I could pack the property method inside the TestContainer, which would remove the need to provide the TestContainer as argument. This is done nicely here.

But I would like to have the helper method in one static class, in case I later decide to optimize my code and remove the method. I managed to get it down to this, but its a little bit ugly (having to provide the string type, looks not very nice).

Any "expression god" knowing a better way. Keep in mind, the static class should be kept universal and not know anything about the TestContainer (otherwise it would be as easy as the link provided)

internal class PropertyNameResolving
{
    internal class TestContainer
    {
        public string LastName { get; set; }
    }

    internal static class BindingHelper
    {
        public static string PropertyName<TObject, TValue>(Expression<Func<TObject, TValue>> propertySelector)
        {
            var memberExpression = propertySelector.Body as MemberExpression;
            if (memberExpression != null) return memberExpression.Member.Name;
            else
            throw new Exception("Something went wrong");
        }
    }

    internal static void Test()
    {
        var t = new TestContainer {LastName = "Hans"};
        Console.WriteLine(BindingHelper.PropertyName<TestContainer, string>(x => x.LastName));
        Console.ReadLine();

    }
}

Btw, the output is "LastName" and can be used to set bindings.

And one more question, can I remove the NULL check safely?

+1  A: 

Because the compiler can imply the type arguments, you shouldn't need to provide at all in the Test() method without changing anything.

Use BindingHelper.PropertyName(x => x.LastName) and it should work fine as is.

You can't remove the null check safely as your expression could be anything, include method call, which wouldn't count as a MemberExpression.

Deeksy
I'd say the null check is unnecessary since you throw anyway if it fails.
Anton Tykhyy
No, this does not work.. Try it :-) "cant infere from usage..." error. I will take a look at Marcs solution.
Christian
+3  A: 

3 options for you:

  • make the class generic, and use inference on the method for the value
  • use an example object for inference on the method
  • forget about the object type entirely and just use an example

These are all shown below. Re the null safety - I would be tempted to check the expression-type (you can also handle methods, btw) - some more code shown here.

using System;
using System.Linq.Expressions;
internal class TestContainer
{
    public string LastName { get; set; }
}
static class Program
{
    static void Main()
    {
        var t = new TestContainer {LastName = "Hans"};            
        string s1 = BindingHelper<TestContainer>
                      .PropertyName(x => x.LastName);            
        string s2 = BindingHelper.PropertyName(t, x => x.LastName);
        string s3 = BindingHelper.PropertyName(() => t.LastName);
    }
}
internal static class BindingHelper
{
    public static string PropertyName<TObject, TValue>(TObject template,
        Expression<Func<TObject, TValue>> propertySelector)
    {
        var memberExpression = propertySelector.Body as MemberExpression;
        if (memberExpression != null) return memberExpression.Member.Name;
        else
            throw new Exception("Something went wrong");
    }
    public static string PropertyName<TValue>(
         Expression<Func<TValue>> propertySelector)
    {
        var memberExpression = propertySelector.Body as MemberExpression;
        if (memberExpression != null) return memberExpression.Member.Name;
        else
            throw new Exception("Something went wrong");
    }
}
internal static class BindingHelper<TObject>
{
    public static string PropertyName<TValue>(
        Expression<Func<TObject, TValue>> propertySelector)
    {
        var memberExpression = propertySelector.Body as MemberExpression;
        if (memberExpression != null) return memberExpression.Member.Name;
        else
            throw new Exception("Something went wrong");
    }
}
Marc Gravell
Thanks, I like method 1 the most... I am sure I will do other things in the BindingHelper later, can't hurt to have the class available anyway. And it looks nice enough..
Christian