表达式解析 - 可以将属性名称数组作为字符串?

时间:2015-02-04 19:54:19

标签: c# .net expression expression-trees dsl

是否可以完成此方法?是否可以在最新版本的C#中使用?将此视为DSL,以配置系统以查看某些对象的某些属性更改。

List<string> list = GetProps<AccountOwner>(x => new object[] {x.AccountOwnerName, x.AccountOwnerNumber}); 
// would return "AccountOwnerName" and "AccountOwnerNumber"

public List<string> GetProps<T>(Expression<Func<T, object[]>> exp)
{  
    // code here
}

2 个答案:

答案 0 :(得分:5)

在C#6中,您将使用:

List<string> list = new List<string>
{
    nameof(AccountOwner.AccountOwnerName),
    nameof(AccountOwner.AccountOwnerNumber)
};

在此之前,您当然可以将表达式树分开 - 最简单的方法是如何使用表达式树可视化工具,或者使用您已获得的代码并在方法中设置断点(只是让它现在返回null)并检查调试器中的表达式树。我确信它不会非常复杂 - 由于数组而比正常情况多一点。

如果你使用:

,你可以使用匿名类型简化它
List<string> list = Properties<AccountOwner>.GetNames(x => new {x.AccountOwnerName, x.AccountOwnerNumber});

然后你可以:

public static class Properties<TSource>
{
    public static List<string> GetNames<TResult>(Func<TSource, TResult> ignored)
    {
        // Use normal reflection to get the properties
    }
}

如果您不关心订购,可以使用

return typeof(TResult).GetProperties().Select(p => p.Name).ToList();

如果你关心排序,你需要查看C#编译器给构造函数参数赋予的名称 - 它有点难看。请注意,我们不需要表达式树 - 我们只需要匿名类型的属性名称。 (诚​​然,表达树也可以正常工作。)

答案 1 :(得分:2)

如果没有c#6和nameof,您可以从表达式树中获取属性名称,如:

using System.Linq.Expressions;
//...
static string GetNameOf<T>(Expression<Func<T>> property)
{
  return (property.Body as MemberExpression).Member.Name;
}

使用它像:

GetNameOf(() => myObject.Property);

不能直接用于对象数组,但是你可以重载一个表达式数组......例如:

static string[] GetNameOf(IEnumerable<Expression<Func<object>>> properties)
{
  return properties.Select(GetNameOf).ToArray();
}

并像

一样使用它
GetNameOf(
     new Expression<Func<object>>[] 
     { 
       () => x.AccountOwnerName, 
       () => x.AccountOwnerNumber
     }
); 

展示小提琴:https://dotnetfiddle.net/GsV96t

更新

如果您选择这条路线,则单个属性的原始GetNameOf不会适用于值类型(因为它们在object中被加到Expression,现在表达式在内部使用Convert。通过将代码更改为:

,可以轻松解决这个问题
static string GetNameOf<T>(Expression<Func<T>> property)
{
  var unary = property.Body as UnaryExpression;
  if (unary != null)
    return (unary.Operand as MemberExpression).Member.Name;
  return (property.Body as MemberExpression).Member.Name;
}

更新了小提琴:https://dotnetfiddle.net/ToXRuu

注意:在这个更新过的小提琴中,我还更新了重载方法以返回List而不是数组,因为原始代码上有什么