2017-05-01 1 views
3

1つのオブジェクトにオブジェクトのリストをマージ:C#の - 私は小さなオブジェクトのリスト渡される

var smalls = new List<Small>(); 
smalls.AddRange(new Small[] { new Small{Name = "Aa", Id = 1, Value = "v1"}, 
           new Small{Name = "Bb", Id = 1, Value = "v2"}, 
           new Small{Name = "Cc", Id = 1, Value = "v3"}, 
           new Small{Name = "Dd", Id = 1, Value = "v4"}, 
           new Small{Name = "Ee", Id = 1, Value = "v5"}, 
           new Small{Name = "Ff", Id = 1, Value = "v6"}, 
           new Small{Name = "Gg", Id = 1, Value = "v7"} }); 

上記リストから、私はこのようになりますオブジェクト移入したいと思います:

var large = new Large 
    { 
     Id = 1, 
     Aa = "v1", 
     Bb = "v2", 
     Cc = "v3", 
     Dd = "v4", 
     Ee = "v5", 
     Ff = "v6", 
     Gg = "v7" 
    } 

現在のコードでは、リストの順序に依存してLargeオブジェクトが生成されますが、これは十分に安全ではなく、リストをオブジェクトにマップする信頼性の高い方法を探しています。

現在のコード:

Large large = new Large 
{ 
    Id = smalls[0].Id, 
    Aa = smalls[0].Value, 
    Bb = smalls[1].Value, 
    Cc = smalls[2].Value, 
    Dd = smalls[3].Value, 
    Ee = smalls[4].Value, 
    Ff = smalls[5].Value, 
    Gg = smalls[6].Value 
} 

だから私は、彼らが正しい順序であるという仮定を排除し、内の対応するフィールドに小さなオブジェクトのName列のオフに基づいて、新しいフィールドを埋めるために探していますラージオブジェクト。

入力いただきありがとうございます。

+0

は、ご注文についてのみ懸念しているか、名前の整合性の考慮がありますか? – DaniDev

+0

大きな質問ですが、私は今注文問題について心配しています。 SmallオブジェクトのNameフィールドのデータは、Largeオブジェクトの対応するフィールド名と常に一致します。 – tvirch

答えて

1

だから私は、彼らが正しい順序

であるという仮定を排除するために探しています、おそらくこのような何か?:

Aa = smalls.Single(s => s.Name == "Aa").Value 

これは、少なくともまだその前提に依存していますレコードの順序は気にしませんが、レコードはまったくあります。その前提を削除したい場合は、エラーチェックを追加することもできます。おそらくこのようなものでしょう:

Aa = smalls.Any(s => s.Name == "Aa") ? smalls.First(s => s.Name == "Aa") : string.Empty 

これは世界で最も効率的なものではありませんが、現在の使用法のように少なくとも1つの行に残ります。複数の行に分けると長くなりますが、実際にはパフォーマンスが問題であっても、実際はそうではありません。

これらの複数の行は、1つの行に戻すためにカスタム拡張メソッドに再組み込みされる可能性がありますか?空は限界です。

Large large = new Large(); 
foreach (var propertyInfo in large.GetType().GetProperties()) 
{ 
    var sm = smalls.FirstOrDefault(small => string.Equals(small.Name, propertyInfo.Name, StringComparison.InvariantCultureIgnoreCase)); 
    if (sm != null) 
     propertyInfo.SetValue(large, Convert.ChangeType(sm.Value, propertyInfo.PropertyType), null); 
} 

重要:このソリューションが動作するためにそれを注意してください、私はあなたの質問に正しく理解している場合

0

、あなたはSmallコレクションの順序を気にすることなくLargeクラスのすべてのプロパティを設定するためにリフレクションを使用することができます更新する必要があるLargeのすべてのプロパティMUSTはgettersとsetterでマークする必要があります。例えば。 public string Aa { get; set; }

Largeのプロパティは、すべてlarge.GetType().GetProperties()を使用して取得します。すべてのプロパティが取得されます。次に、Smallクラスコレクション内の.Nameプロパティと名前を比較し、一致するものが見つかるとプロパティの値を設定します。反射についてもっと読むことができますhereLarge

スクリーンショットそれを試した後:

private static string GetValueByName(IDictionary<string,string> data, string name) { 
    string res; 
    return data.TryGetValue(name, out res) ? res : null; 
} 
private static Large MakeFromAttributes(IEnumerable<Small> data, int id) { 
    var byName = data.ToDoctionary(s => s.Name, s => s.Value); 
    return new Large { 
     Id = id 
    , Aa = GetValueByName(byName, "Aa") 
    , Bb = GetValueByName(byName, "Bb") 
    , Cc = GetValueByName(byName, "Cc") 
    , Dd = GetValueByName(byName, "Dd") 
    , Ee = GetValueByName(byName, "Ee") 
    , Ff = GetValueByName(byName, "Ff") 
    , Gg = GetValueByName(byName, "Gg") 
    }; 
} 

付:

2

あなたはグループ値Idによって、およびNameフィールドに基づいて値を抽出するためのいくつかのメソッドを作ることができますこれらのヘルパーメソッドでは、次のようにLINQクエリを作成できます。

​​
0

あなたはSmall年代のリストは、その後、リフレクションを使用して、グループおよびその他のプロパティのKeyとしてIdを設定されたグループは、より適切なデータ構造であってもよい。この

var large = smalls.GroupBy(small => small.Id) 
    .Select(group => 
    { 
     var result = new Large(); 
     result.Id = group.Key; 
     var largeType = result.GetType(); 
     foreach (var small in group) 
     { 
       largeType.GetProperty(small.Name).SetValue(result, small.Value); 
     } 
     return result; 
    }).First(); 
1

Dictionary(TKey, TValue)次のようになりますことができますKeysは動的であり、IEnumerable(Small)からLargeに向かうすべてのソリューションは、コレクションまたは集約オブジェクトの構成を前提にする必要があるため、ユースケースを使用する必要があります。

単純な動的ソリューションはリフレクションを使用することですが、これは既に提案されている静的ルックアップと比べてオーバーヘッドが大きくなります。

public static Large CreateLargeFromSmalls(int id, IEnumerable<Small> smalls) 
{ 
    var largeType = typeof(Large); 
    var large = new Large { Id = id }; 

    foreach (var small in smalls) 
    { 
     var prop = largeType.GetProperty(small.Name); 
     if (prop != null) 
     { 
      prop.SetValue(large, small.Value); 
     } 
    } 

    return large; 
} 

仮定

  • SmallNameは正確に対応するLargeプロパティと一致します。
  • SmallNameはユニークではなく、繰り返しの順序が重要です。
  • SmallNameに対応するプロパティがLargeに存在しない場合、マップされません。 Largeから

賛否

  • 契約の変更は、マッピング・ロジックには影響を与えません。

短所

  • オーバーヘッド反射

例:

var smalls = new List<Small> 
{ 
    new Small{Name = "Aa", Id = 1, Value = "v1"}, 
    new Small{Name = "Bb", Id = 1, Value = "v2"}, 
    new Small{Name = "Cc", Id = 1, Value = "v3"}, 
    new Small{Name = "Dd", Id = 1, Value = "v4"}, 
    new Small{Name = "Ee", Id = 1, Value = "v5"}, 
    new Small{Name = "Ff", Id = 1, Value = "v6"}, 
    new Small{Name = "Gg", Id = 1, Value = "v7"} 
}; 

var bigs = 
    smalls 
     .GroupBy(x => x.Id) 
     .Select(g => CreateLargeFromSmalls(g.Key, g)) 
     .ToList(); 
+0

私は同じ考えを持っていた! –

関連する問題