0

I'm writing an utility class, that take a class name and array of property names as params like this:

public static void DoMagic(Type type, params string[] include)

and call it looks like this:

Helper.DoMagic(typeof(MyClass), "ClientId", "PointId", "SerialNumber")

But i don't like it, couse there is no compile-check, and if i make mistake in string params, it will only runtime error, not compile error.

I want to do something like this:

Helper.DoMagic<MyClass>(x => x.ClientId, x => x.PointId, x => x.SerialNumber)

Or, may be, even shorter. Is there any way to do this?

Timur Lemeshko
  • 2,747
  • 5
  • 27
  • 39

2 Answers2

1

if you want syntax

Helper.DoMagic<MyClass>(x => x.ClientId, x => x.PointId, x => x.SerialNumber)

you need declare method as

public static IEnumerable<FieldInfo> DoMagic<T>(params Expression<Func<T, object>>[] include)
{
    foreach(Expression<Func<T, object>> tree in include)
    {
        FieldInfo fi = null;

        // tree parser, which gets field info

        yield return fi;
    }
}

SO: Retrieving Property name from lambda expression

it will save you from typos, but create other issues:

// method call
DoMagic<MyClass>(c => c.ToString().Length);
Community
  • 1
  • 1
ASh
  • 34,632
  • 9
  • 60
  • 82
1

Thanks ASh and Retrieving Property name from lambda expression, I resolve my problem by parsing expression tree:

public static class Helper
{
    public static void DoMagic<T>(params Expression<Func<T, object>>[] include) 
    {
        var infos = include.Select(GetPropertyInfo).ToList();

        //do any magic
        foreach (var propertyInfo in infos)
        {
            Console.WriteLine(propertyInfo.Name);
        }
    }

    /// <summary>
    ///     Get PropertyInfo form Expression tree
    /// </summary>
    private static PropertyInfo GetPropertyInfo<TSource, TProperty>(
        Expression<Func<TSource, TProperty>> propertyLambda)
    {
        var type = typeof (TSource);

        var expressionCast = propertyLambda.Body as UnaryExpression;

        // this for boxed types
        var expression = propertyLambda.Body as MemberExpression;


        if (expressionCast == null && expression == null)
        {
            throw new ArgumentException(string.Format(
                "Expression '{0}' is not a MemberExpression ",
                propertyLambda));
        }

        // this for boxed types
        if (expression == null)
        {
            expression = expressionCast.Operand as MemberExpression;

            if (expression == null)
            {
                throw new ArgumentException(string.Format(
                    "Expression '{0}' is not a MemberExpression",
                    propertyLambda));
            }
        }

        var member = expression.Member;

        if (member == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a method, not a property.",
                propertyLambda));


        var propInfo = member as PropertyInfo;
        if (propInfo == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a field, not a property.",
                propertyLambda));

        if (type != propInfo.ReflectedType &&
            !type.IsSubclassOf(propInfo.ReflectedType))
            throw new ArgumentException(string.Format(
                "Expresion '{0}' refers to a property that is not from type {1}.",
                propertyLambda,
                type));

        return propInfo;
    }
}

public class MyClass
{
    public int ClientId { get; set; }
    public int PointId { get; set; }
    public string SerialNumber { get; set; }
}

internal class Program
{
    private static void Main(string[] args)
    {
        Helper.DoMagic<MyClass>(c => c.ClientId, c => c.PointId, c => c.SerialNumber);
        Console.ReadLine();
    }
}

But what I was really need, is just new c# 6.0 feature nameof():

Helper.DoMagic<MyClass>(nameof(myvar.ClientId), nameof(myvar.PointId), nameof(myvar.SerialNumber));

Simple Like This!

Community
  • 1
  • 1
Timur Lemeshko
  • 2,747
  • 5
  • 27
  • 39
  • well done! i suggest to put line with `nameof` on top of your answer for future readers – ASh Sep 22 '15 at 08:56