使用 lambda 表达式来避免使用“魔术字符串”指定一个属性
我正在编写一项服务来获取特定类型的对象集合,并且 将其原语、字符串和 DateTime 类型输出到 CSV 格式。我有以下两种说法。我发现基于 lambda 的版本要干净得多。
魔术字符串版本
string csv = new ToCsvService<DateTime>(objs)
.Exclude("Minute")
.ChangeName("Millisecond", "Milli")
.Format("Date", "d")
.ToCsv();
与Lambda 版本
string csv = new ToCsvService<DateTime>(objs)
.Exclude(p => p.Minute)
.ChangeName(p => p.Millisecond, "Milli")
.Format(p => p.Date, "d")
.ToCsv();
根据 Jon Skeet 的建议,所有 lambda 方法都共享相似的方法签名,
public IToCsvService<T> Exclude<TResult>(
Expression<Func<T, TResult>> expression)
然后我将 expression.Body
传递给 FindMemberExpression
。我改编了 中的代码
nhlambdaextensions 项目 中 ExpressionProcessor.cs 的 FindMemberExpression
方法。我的 FindMemberExpression
的非常相似的版本如下:
private string FindMemberExpression(Expression expression)
{
if (expression is MemberExpression)
{
MemberExpression memberExpression = (MemberExpression)expression;
if (memberExpression.Expression.NodeType == ExpressionType.MemberAccess
|| memberExpression.Expression.NodeType == ExpressionType.Call)
{
if (memberExpression.Member.DeclaringType.IsGenericType
&& memberExpression.Member.DeclaringType
.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if ("Value".Equals(memberExpression.Member.Name))
{
return FindMemberExpression(memberExpression.Expression);
}
return String.Format("{0}.{1}",
FindMemberExpression(memberExpression.Expression),
memberExpression.Member.Name);
}
}
else
{
return memberExpression.Member.Name;
}
}
throw new Exception("Could not determine member from "
+ expression.ToString());
}
我正在 FindMemberExpression
中测试足够的案例吗?考虑到我的用例,我所做的事情是否太过分了?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑:使这个更简单的核心是将方法的签名也更改为结果类型中的通用:
这样您就不会得到转换表达式,因为不需要转换。例如,
p =>由于类型推断,p.Minute
将自动以Expression>
结束。在我看来,这似乎有点矫枉过正,因为目前您所需要的只是一个属性 - 至少,这就是您的示例所显示的全部内容。
为什么不从识别属性开始,然后在需要时扩展它呢??
编辑:这是一个简短但完整的示例,未显示任何转换:
如果将表达式类型更改为
Expression>
但是,它会 显示Convert(...)
位。我怀疑您需要更改Exclude
(等)方法的签名。EDIT: The core to making this simpler is to change the signature of your methods to be generic in the result type too:
That way you won't end up with a conversion expression because no conversion will be necessary. For example,
p => p.Minute
will end up as anExpression<Func<DateTime, int>>
automatically due to type inference.It looks like overkill to me, given that at the moment all you need is a property - at least, that's all that your sample shows.
Why not start off just recognising a property, and expand it later if you need to?
EDIT: Here's a short but complete example which doesn't show any conversions:
If you change the expression type to
Expression<Func<DateTime, long>>
however, it does show theConvert(...)
bit. I suspect you need to change the signatures of yourExclude
(etc) methods.您是否有计划让它变得更加灵活,或者这就是它需要做的一切?
理想情况下,您应该拥有最简单的代码来完成您需要做的事情,这样您就可以减少可能出错的事情的数量。
如果您这样做是为了概念证明,并且知道稍后您将需要 lambda 表达式,那么将它们保留在那里是有意义的,但是,如果这是最终产品,那么前一个更容易阅读,并且不太可能如果其他人需要更改代码,则会造成混乱。
Do you have any plans on make it more flexible, or is this all that it needs to do?
Ideally you should have the simplest code that will do what you need done, so that you can decrease the number of things that can go wrong.
If you are doing this as a proof of concept, and know that later you will need lambda expressions, then it makes sense to keep them there, but, if this is the final product then the former one is easier to read, and less likely to be a cause of confusion if someone else needs to make changes to the code.