6

特定の型のオブジェクトのコレクションを取得し、そのプリミティブ型、文字列型、および DateTime 型CSV Formatの文字列に出力するサービスを作成しています。以下のステートメントの両方が機能しています。ラムダベースのバージョンの方がずっときれいだと思います。

魔法のひものバージョン

string csv = new ToCsvService<DateTime>(objs)
    .Exclude("Minute")
    .ChangeName("Millisecond", "Milli")
    .Format("Date", "d")
    .ToCsv();

vs. Lambda バージョン

string csv = new ToCsvService<DateTime>(objs)
    .Exclude(p => p.Minute)
    .ChangeName(p => p.Millisecond, "Milli")
    .Format(p => p.Date, "d")
    .ToCsv();

Jon Skeet の推奨に従って、すべてのラムダ メソッドは同様のメソッド シグネチャを共有します。

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

expression.Body次に、をに渡し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.MinuteExpression<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(etc) メソッドの署名を変更する必要があると思われます。

于 2010-07-25T19:52:42.883 に答える
4

より柔軟にする計画はありますか、それともこれで十分ですか?

理想的には、必要なことを実行する最も単純なコードを用意して、問題が発生する可能性のあるものの数を減らすことができるようにする必要があります。

これを概念実証として行っており、後でラムダ式が必要になることがわかっている場合は、ラムダ式を保持することは理にかなっていますが、これが最終製品である場合、前者の方が読みやすく、可能性は低くなります。他の誰かがコードを変更する必要がある場合、混乱の原因となります。

于 2010-07-25T19:55:47.073 に答える