属性名称为带有编译检查的参数

时间:2015-09-21 09:31:52

标签: c# linq generics reflection

我正在编写一个实用程序类,它将类名和属性名称数组作为这样的参数:

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

并将其称为:

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

但是我不喜欢它,没有编译检查,如果我在字符串参数中出错,它只会运行时错误,而不是编译错误。

我想做这样的事情:

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

或者,可能更短。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:1)

如果你想要语法

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

你需要声明方法为

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

它可以帮助您避免拼写错误,但会产生其他问题:

// method call
DoMagic<MyClass>(c => c.ToString().Length);

答案 1 :(得分:1)

感谢ASh和Retrieving Property name from lambda expression,我通过解析表达式树来解决我的问题:

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();
    }
}

但我真正需要的只是新的c#6.0功能 nameof()

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

简单就像这样!