使类参数的属性成为函数

时间:2019-06-05 14:34:07

标签: c# linq lambda reflection

我的意图是传递一个类的公共属性,例如:

class MyTestClass
{
    public string Name { get; set; }
    public DateTime  StartedAt { get; set; }
    public TimeSpan Duration { get; set; }
}

对函数使用参数:

static void MyCustomFunc(params Expression<Func<MyTestClass, object>>[] props)
{
    foreach (var p in props)
    {
        // The following only works for Name property, not for StartedAt or Duration
        MemberExpression member = p.Body as MemberExpression;
        PropertyInfo propertyInfo = (PropertyInfo)member.Member;

        string name = propertyInfo.Name;
        Type type = propertyInfo.PropertyType;
        Func<MyTestClass, object> func = p.Compile();
    }
}

该函数应该收集此信息并将其提供给导出器类,该类将MyTestClass对象集导出到CSV文件。

写入CSV文件的输出取决于送入MyCustomFunc的属性的数量,类型和顺序。

所以这个:

MyCustomFunc(x => x.Name, x => x.StartedAt);

产生与以下结果不同的结果:

MyCustomFunc(x => x.StartedAt, x => x.Name);

MyCustomFunc(x => x.StartedAt, x => x.Name, x => x.Duration);

不同
MyCustomFunc(x => x.Duration, x => x.StartedAt, x => x.Name);

我的问题是使反射起作用。由于某些原因,我无法理解p.Body

  • 对于{x => x.Name}等于{x.Name},但
  • 对于{x => x.StartedAt}等于{Convert(x.StartedAt)}

第一个可以由

处理
MemberExpression member = p.Body as MemberExpression;

但是第二个返回null,所以我得到一个空引用异常。

1 个答案:

答案 0 :(得分:4)

对类型参数进行硬编码的工作使我有点头疼,所以我改变了这一点。我有种感觉,您接下来将要弄混这一部分。让我知道是否不是这种情况,我会改回来。

public static void MyCustomFunc<T>(this T inst, params Expression<Func<T, object>>[] props)
{
    foreach (var p in props)
    {
        PropertyInfo propertyInfo = null;

        //  Because the return type of the lambda is object, when the property is a value 
        //  type, the Expression will have to be a unary expression to box the value. 
        //  The MemberExpression will be the operand from that UnaryExpression. 
        if (p.Body is UnaryExpression ue && ue.Operand is MemberExpression ueMember)
        {
            propertyInfo = (PropertyInfo)ueMember.Member;
        }
        else if (p.Body is MemberExpression member)
        {
            propertyInfo = (PropertyInfo)member.Member;
        }
        else
        {
            throw new ArgumentException("Parameters must be property access expressions " 
                + "in the form x => x.Property");
        }

        string name = propertyInfo.Name;
        Type type = propertyInfo.PropertyType;
        Func<T, object> func = p.Compile();
    }
}

用法:

new MyTestClass { Name = "Stan", StartedAt = DateTime.Now }
    .MyCustomFunc(x => x.Name, x => x.StartedAt);