2009-10-18 56 views
7

my recent question开始,我尝试通过在域接口中包含一些愚蠢的逻辑来集中域模型。但是,我发现一些问题需要包含或排除某些属性进行验证。在C#中定义和访问所选属性的最佳方式是什么?

基本上,我可以像下面的代码一样使用表达式树。不过,我不喜欢它,因为每次创建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 
); 

感谢,

回答

9

Lambda表达式是伟大的很多场景 - 但是如果你不想让他们,也许根本就不使用它们?我讨厌这么说,但简单的字符串已经过尝试和测试,尤其是对于像数据绑定这样的场景。如果你想快速访问,你可以看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 }); 

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

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

一旦你知道MemberInfo S(me.Member在上面),建立自己的lambda表达式为单独的访问应该是微不足道的。例如(包括强制转换为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(); 
+0

哦,好一个:) – 2009-10-18 19:11:04

+0

什么是最好的方式保持选定的属性以便快速访问?列表? – 2009-10-19 03:01:40

+0

'MemberInfo'会很好; ''Func '(或'Func ')会很好;一个'PropertyDescriptor'会很好(尤其是使用HyperDescriptor)。它会以任何方式工作... – 2009-10-19 04:03:50

1

这里是最短的表情我能想出:

public static void IncludeProperties(Expression<Action<IUser>> selectedProperties) 
{ 
    // some logic to store parameter 
} 

public static void S(params object[] props) 
{ 
    // dummy method to get to the params syntax 
} 

[Test] 
public void ParamsTest() 
{ 
    IncludeProperties(u => S(
     u.Id, 
     u.Name 
     )); 

} 
+0

如果您使用匿名类型和初始值设定项(请参阅我的更新答案),您不需要虚拟方法。这是不错的 – 2009-10-18 19:04:21

+0

是的,我现在看到:) – 2009-10-18 19:12:06

相关问题