このコードスニペットから重複を削除する

このスニペットから重複を削除する際のアドバイスを探している:

foreach (Car car in carList) {
    DataRow row = NewRow();

    StringBuilder sbConfigurations = new StringBuilder();    
    foreach (ConfigurationItem configurationItem in car.Configurations)
        sbConfigurations.AppendFormat("{0}: {1}\n", configurationItem.Name, configurationItem.Value);

    row["configurations"] = sbConfigurations;


    StringBuilder sbOptionals = new StringBuilder();
    foreach (OptionalItem optionalItem in car.Optionals) 
        sbOptionals.AppendFormat("{0}, ", optionalItem.Name);

    row["optionals"] = sbOptionals;

    Rows.Add(row);
}

編集:これは単純化されたコンテキストです、これらのようなより多くのリスト結合があるかもしれません

2
私はインデックスの名前を持つ配列を使って何かを考えていましたが、次に car.Optionals を呼び出していることがわかりました。あなたは反射を使ってこれを行うことができますが、それはそれを良くしません。
追加された 著者 Marnix,
構成とオプションは共通の基本クラスから派生していますか?そうでなければ、有意な簡素化にはおそらく反映が含まれます。これをたくさんするつもりなら、obj.FormattedOutput( "{Name}:{Value} \ n")のような関数を書く努力を正当化することができます
追加された 著者 Raymond Chen,

3 答え

私は本当にあなたが "重複"が必要であると言っているものを削除するとは思わない。同一のコードが2回出現するのではなく、同じようなコードが2回出現します。これは一般的であり、心配することはありません。

3
追加された
@arkilus:うまくいくことができますが、このようなシンプルなケースで意味をなさないかどうか分からず、1分で解決策を投稿します
追加された 著者 sll,
それはポイントだけど、まだ私は列の中に挿入リストを抽象化するために何かを実装できると思う。
追加された 著者 Yuri Ghensev,
私の例では、1回の "繰り返し"しかありません。もしこれらのような列を追加するとどうなりますか?
追加された 著者 Yuri Ghensev,

私は多くの重複はありませんが、Linq Extensionsへのこの「文字通りの翻訳」 あなたが探しているものです(ブラウザで入力するので、まだテストされていません - まだ):

foreach (Car car in carList) {
    DataRow row = NewRow();

    row["configurations"] = car.Configurations.Aggregate(new StringBuilder(), (a,i) => a.AppendFormat("{0}: {1}\n", i.Name, i.Value));
    row["optionals"] = car.Optionals.Aggregate(new StringBuilder(), (a,i) => a.AppendFormat("{0}, ", i.Name));

    Rows.Add(row);
}

代わりに、stringbuildersを使わずに読みやすく(/効率的に)書くことができます:

ラムダを抽出すると、行が短くなりました。

Func nameValue = car => string.Format("{0}: {1}\n", car.Name, car.Value);

foreach (var car in carList) {
    var row = new Dictionary();

    row["configurations"] = string.Join("\n", car.Configurations.Select(nameValue));
    row["optionals"]      = string.Join(", ", car.Optionals.Select(i => i.Name));

    list.Add(row);
}

string.Join の2番目のパラメータで追加の .ToArray()呼び出しを行う必要があります。

2
追加された
Hehe。それをもう少し改善しました - 「長い行」の苦情に対処してください。
追加された 著者 sehe,
ちょうど新しいC#の特徴を学びました:P、私は同じ行に関数呼び出しが多すぎると思いますが、きれいなコードも探しています。
追加された 著者 Yuri Ghensev,

問題を逆さまにするのはどうですか?関数に各オブジェクトの DataRow 形式を理解させる代わりに、各オブジェクトに DataRow 形式を理解させるようにしてください。 Object.ToString() Object.ToString()として実装していない場合、 ConfigurationItem OptionalItem

class ConfigurationItem
{
    public string override ToString()
    {
        return string.Format("{0}: {1}\n", Name, Value);
    }
}

class OptionalItem
{
    public string override ToString()
    {
        return string.Format("{0}, ", Name);
    }
}

これで、すべてのタイプのオブジェクトに単一のループを使用できます。

string BuildDataRowString(IEnumerable collection)
{
    var sb = new StringBuilder();
    foreach (var o in collection) sb.Append(o.ToString());
    return sb.ToString();
}

row["configurations"] = car.Configurations.BuildDataRowString();
row["optionals"] = car.Optionals.BuildDataRowString();

他の目的で object.ToString()が必要な場合は、 " DataRow "形式のカスタムフォーマットを追加できます:

class ConfigurationItem : IFormattable
{
    public string override ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "D") {
            return string.Format(formatProvider, "{0}: {1}\n", Name, Value);
        }
        return this.ToString();//otherwise format as default
    }
}

class OptionalItem : IFormattable
{
    public string override ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "D") {
            return string.Format(formatProvider, "{0}, ", Name);
        }
        return this.ToString();//otherwise format as default
    }
}

string BuildDataRowString(this IEnumerable e, string format)
{
    StringBuilder sb = new StringBuilder();
    foreach (var o in e) sb.AppendFormat("{0:D}", o);
    return sb.ToString();
}
2
追加された