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

Expression parsing - Possible to get array of property names as string?

这个方法可以完成吗?在最新版本的 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
}

在 C# 6 中,您将使用:

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

在此之前,您当然可以将表达式树分开 - 最简单的方法可能是使用表达式树可视化工具,或者使用您获得的代码并在方法中放置一个断点(暂时将其设置为 return 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# 编译器为构造函数参数提供的名称 - 这有点难看。请注意,虽然我们不需要表达式树 - 我们只需要来自匿名类型的 属性 名称。 (无可否认,表达式树也可以。)

如果没有 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
     }
); 

展示 fiddle:https://dotnetfiddle.net/GsV96t

更新

如果你走这条路,单个 属性 的原始 GetNameOf 将不适用于值类型(因为它们在 [=17= 中被装箱到 object ],现在表达式在内部使用 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;
}

已更新 fiddle:https://dotnetfiddle.net/ToXRuu

注意:在这个更新的 fiddle 中,我还将重载方法更新为 return a List 而不是数组,因为那是什么你的原始代码