6

我正在编写一个服务来获取特定类型的对象的集合,并将其原始、字符串和 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.Bodyto FindMemberExpression。我已经从nhlambdaextensions 项目FindMemberExpression的 ExpressionProcessor.cs 方法中改编了代码。我非常相似的版本如下: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?考虑到我的用例,我正在做的事情是否矫枉过正?

4

2 回答 2

7

编辑:使这更简单的核心是将方法的签名更改为在结果类型中也是通用的:

public IToCsvService<TSource> Exclude<TResult>(
    Expression<Func<TSource, TResult>> expression)

这样你就不会得到一个转换表达式,因为不需要转换。例如,由于类型推断,p => p.Minute将自动结束。Expression<Func<DateTime, int>>


对我来说,这看起来有点矫枉过正,因为目前您所需要的只是一个属性 - 至少,这就是您的样本所显示的全部内容。

为什么不从识别属性开始,然后在需要时扩展它呢?

编辑:这是一个简短但完整的示例,不显示任何转换:

using System;
using System.Linq.Expressions;

class Test
{
    static void Main()
    {
        Expression<Func<DateTime, int>> dt = p => p.Minute;
        Console.WriteLine(dt);
    }
}

如果将表达式类型更改为Expression<Func<DateTime, long>>但是,它显示该Convert(...)位。我怀疑您需要更改Exclude(等)方法的签名。

于 2010-07-25T19:52:42.883 回答
4

您是否有任何计划让它更灵活,或者这就是它需要做的全部?

理想情况下,您应该拥有最简单的代码来完成您需要完成的工作,这样您就可以减少可能出错的事情的数量。

如果您这样做是为了证明概念,并且知道稍后您将需要 lambda 表达式,那么将它们保留在那里是有意义的,但是,如果这是最终产品,那么前者更容易阅读,而且不太可能如果其他人需要对代码进行更改,则会引起混淆。

于 2010-07-25T19:55:47.073 回答