使用 lambda 表达式来避免使用“魔术字符串”来指定属性

2024-02-21

我正在编写一项服务来获取特定类型的对象集合输出其原始类型、字符串类型和日期时间类型 https://stackoverflow.com/questions/3161959/in-c-is-there-a-way-retrieve-only-built-in-data-type-properties-using-reflection到一个字符串CSV 格式 http://en.wikipedia.org/wiki/Comma-separated_values。我有以下两种说法。我发现基于 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 to FindMemberExpression。我已经改编了代码FindMemberExpressionExpressionProcessor.cs 的方法 http://code.google.com/p/nhlambdaextensions/source/browse/trunk/Source/ExpressionProcessor.cs#123来自nhlambda扩展项目 http://code.google.com/p/nhlambdaextensions/。我的版本非常相似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?考虑到我的用例,我所做的事情是否太过分了?


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

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>>然而,它does显示Convert(...)少量。我怀疑你需要更改你的签名Exclude(等)方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 lambda 表达式来避免使用“魔术字符串”来指定属性 的相关文章

随机推荐