属性 names as params 编译检查

property names as params with compile check

我正在编写一个实用程序 class,它将 class 名称和 属性 名称数组作为参数,如下所示:

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)

或者,可能更短。有什么办法吗?

如果你想要语法

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

感谢 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));

像这样简单!