3

このサイトの質問を調べましたが、特定の問題に一致するものが見つかりませんでした。

私が次のものを持っていると仮定します:

Product[] store1 = { new Product { Name = "apple", Code = 9, Code1="1" }, 
                   new Product { Name = "orange", Code = 4 } };

Product[] store2 = { new Product { Name = "apple", Code = 9, Code2="2" }, 
                   new Product { Name = "lemon", Code = 12 } };

と:

public class Product : IEquatable<Product>
{
    public string Name { get; set; }
    public int Code { get; set; }
    public string Code1 { get; set; }
    public string Code2 { get; set; }

    public bool Equals(Product other)
    {

        //Check whether the compared object is null. 
        if (Object.ReferenceEquals(other, null)) return false;

        //Check whether the compared object references the same data. 
        if (Object.ReferenceEquals(this, other)) return true;

        //Check whether the products' properties are equal. 
        return Code.Equals(other.Code) && Name.Equals(other.Name);
    }

    // If Equals() returns true for a pair of objects  
    // then GetHashCode() must return the same value for these objects. 

    public override int GetHashCode()
    {

        //Get hash code for the Name field if it is not null. 
        int hashProductName = Name == null ? 0 : Name.GetHashCode();

        //Get hash code for the Code field. 
        int hashProductCode = Code.GetHashCode();

        //Calculate the hash code for the product. 
        return hashProductName ^ hashProductCode;
    }
}

一致した場合に store2 のデータで上書きされ、一致しない場合に store2 から store1 に挿入された store1 のデータを含む単一の Enumerable を返すにはどうすればよいですか。基本的に、TSQL Merge ステートメントに相当する C# を探しています。

これを実行する日の最後に:

foreach (var product in union)
      Console.WriteLine(product.Name + " " + product.Code + " " + product.Code1 + " " + product.Code2);

戻りたい:

りんご 9 1 2

オレンジ 4

レモン 12

ただし、これを実行すると:

IEnumerable<Product> union = store1.Union(store2);

私は得る:

りんご 9 1

オレンジ 4

レモン 12

そして、これを実行すると:

IEnumerable<Product> union = store1.Concat(store2);

私は得る:

りんご 9 1

オレンジ 4

アップル 9 2

レモン 12

助けてくれてありがとう。

4

2 に答える 2

0

リフレクションに頼るのではなく、Productクラスで独自の機能を記述します。AsComboorメソッドのようなものCombineWith:

public IEnumerable<Product> AsCombo(Product p)
{
    //if not equal, return both
    if (!Equals(p))
    {
        yield return this;
        yield return p;
        yield break;
    }

    //if equal return the one desired by checking all properties
    yield return new Product //always better to return new instance for linq queries
    { 
        Name = Name, 
        Code = Code, 
        Code1 = Code1 ?? p.Code1, //I give preference to 'this'
        Code2 = Code2 ?? p.Code2  //I give preference to 'this'
    };
}

これで、すべての標準的な Linq クエリが機能するはずです。

var combo = store1.Concat(store2)
                  .GroupBy(x => x)
                  .Where(x => x.Count() == 1)
                  .Select(x => x.Key) //get non duplicated products
                  .Concat(store1.Distinct() //concat them with combined form of duplicated products
                                .Join(store2.Distinct(), x => x, x => x, (x, y) => x.AsCombo(y))
                                .SelectMany(x => x))
                  .ToList();

以下のクエリでは少し簡単ですが、それはの実装に依存しています(最初または外側のシーケンスの複製を保持し、後続/内側のシーケンスからの複製を破棄するとUnion仮定します)。Union推奨されません。

var combo = store1.Join(store2, x => x, x => x, (x, y) => x.AsCombo(y))
                  .SelectMany(x => x)
                  .Union(store1)
                  .Union(store2)
                  .ToList();
于 2013-11-09T11:55:36.957 に答える