在C#中定义和访问所选属性的最佳方法是什么?

Sou*_*ter 7 c# lambda

我最近的问题,我尝试通过在域界面中包含一些愚蠢的逻辑来集中域模型.但是,我发现了一些需要在验证中包含或排除某些属性的问题.

基本上,我可以像下面的代码一样使用表达式树.不过,我不喜欢它,因为每次创建lambda表达式时我都需要定义局部变量("u").你有比我短的源代码吗?此外,我需要一些方法来快速访问选定的属性.

public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
    // some logic to store parameter   
}

IncludeProperties<IUser>
(
    u => u.ID,
    u => u.LogOnName,
    u => u.HashedPassword
);
Run Code Online (Sandbox Code Playgroud)

谢谢,

Mar*_*ell 9

Lambdas适用于许多场景 - 但如果您不想要它们,可能根本就不使用它们?我不想这么说,但是对简单的字符串进行了尝试和测试,特别是对于数据绑定等场景.如果你想要快速访问,你可以查看HyperDescriptor,或者有方法编译属性访问器的委托,或者你可以Expression从字符串构建一个并编译它(object如果你想要一个已知的签名,包括一个强制转换,而不是调用(慢得多)DynamicInvoke).

当然,在大多数情况下,即使粗反射也足够快,而且不是瓶颈.

我建议从最简单的代码开始,检查它实际上是太慢了,然后再担心它的速度很快.如果不是太慢,请不要更改它.除非上述任何选项都有效.


另一个想法; 如果您正在使用Expression,您可以执行以下操作:

public void IncludeProperties<T>(
    Expression<Func<T,object>> selectedProperties)
{
    // some logic to store parameter   
}

IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
Run Code Online (Sandbox Code Playgroud)

然后把表达分开?有点整洁,至少......这里有一些展示解构的示例代码:

public static void IncludeProperties<T>(
    Expression<Func<T, object>> selectedProperties)
{
    NewExpression ne = selectedProperties.Body as NewExpression;
    if (ne == null) throw new InvalidOperationException(
          "Object constructor expected");

    foreach (Expression arg in ne.Arguments)
    {
        MemberExpression me = arg as MemberExpression;
        if (me == null || me.Expression != selectedProperties.Parameters[0])
            throw new InvalidOperationException(
                "Object constructor argument should be a direct member");
        Console.WriteLine("Accessing: " + me.Member.Name);
    }
}
static void Main()
{
    IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Run Code Online (Sandbox Code Playgroud)

一旦你知道MemberInfos(me.Member在上面),为个人访问建立你自己的lambdas应该是微不足道的.例如(包括object获取单个签名的强制转换):

var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Run Code Online (Sandbox Code Playgroud)