C# Linq 中的 Union 与 Concat
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13417556/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Union Vs Concat in Linq
提问by Prasad Kanaparthi
I have a question on Unionand Concat. I guess both are behaving same in case of List<T>.
我有一个关于Union和的问题Concat。我想两者在List<T>.
var a1 = (new[] { 1, 2 }).Union(new[] { 1, 2 });             // O/P : 1 2
var a2 = (new[] { 1, 2 }).Concat(new[] { 1, 2 });            // O/P : 1 2 1 2
var a3 = (new[] { "1", "2" }).Union(new[] { "1", "2" });     // O/P : "1" "2"
var a4 = (new[] { "1", "2" }).Concat(new[] { "1", "2" });    // O/P : "1" "2" "1" "2"
The above result are expected,
以上结果在意料之中,
But Incase of List<T>I am getting same result.
但是List<T>如果我得到相同的结果。
class X
{
    public int ID { get; set; }
}
class X1 : X
{
    public int ID1 { get; set; }
}
class X2 : X
{
    public int ID2 { get; set; }
}
var lstX1 = new List<X1> { new X1 { ID = 10, ID1 = 10 }, new X1 { ID = 10, ID1 = 10 } };
var lstX2 = new List<X2> { new X2 { ID = 10, ID2 = 10 }, new X2 { ID = 10, ID2 = 10 } };
var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>());     // O/P : a5.Count() = 4
var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>());    // O/P : a6.Count() = 4
But both are behaving the same incase of List<T>.
但是两者的行为都相同List<T>。
Any suggestions please?
请问有什么建议吗?
采纳答案by Sergey Berezovskiy
Union returns Distinctvalues. By default it will compare references of items. Your items have different references, thus they all are considered different. When you cast to base type X, reference is not changed.
联合返回Distinct值。默认情况下,它将比较项目的引用。您的项目有不同的参考,因此它们都被认为是不同的。当您转换为 base type 时X,引用不会更改。
If you will override Equalsand GetHashCode(used to select distinct items), then items will not be compared by reference:
如果您将覆盖Equals和GetHashCode(用于选择不同的项目),则项目将不会通过引用进行比较:
class X
{
    public int ID { get; set; }
    public override bool Equals(object obj)
    {
        X x = obj as X;
        if (x == null)
            return false;
        return x.ID == ID;
    }
    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
}
But all your items have different value of ID. So all items still considered different. If you will provide several items with same IDthen you will see difference between Unionand Concat:
但是你所有的物品都有不同的价值ID。所以所有项目仍然被认为是不同的。如果您将提供多个相同的项目,ID那么您将看到Union和之间的区别Concat:
var lstX1 = new List<X1> { new X1 { ID = 1, ID1 = 10 }, 
                           new X1 { ID = 10, ID1 = 100 } };
var lstX2 = new List<X2> { new X2 { ID = 1, ID2 = 20 }, // ID changed here
                           new X2 { ID = 20, ID2 = 200 } };
var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>());  // 3 distinct items
var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>()); // 4
Your initial sample works, because integers are value types and they are compared by value.
您的初始示例有效,因为整数是值类型,它们按值进行比较。
回答by Rawling
Concatliterally returns the items from the first sequence followed by the items from the second sequence. If you use Concaton two 2-item sequences, you will always get a 4-item sequence.
Concat从字面上返回第一个序列中的项目,然后是第二个序列中的项目。如果您Concat在两个 2 项序列上使用,您将始终获得 4 项序列。
Unionis essentially Concatfollowed by Distinct.
Union基本上Concat是Distinct.
In your first two cases, you end up with 2-item sequences because, between them, each pair of input squences has exactly two distinct items.
在前两种情况下,您最终会得到 2 项序列,因为在它们之间,每对输入序列恰好有两个不同的项。
In your third case, you end up with a 4-item sequence because all four items in your two input sequences are distinct.
在第三种情况下,您最终得到一个 4 项序列,因为两个输入序列中的所有四个项都是不同的。
回答by Tim Schmelter
Unionand Concatbehave the same since Unioncan not detect duplicates without a custom IEqualityComparer<X>. It's just looking if both are the same reference. 
Union并且Concat行为相同,因为Union没有 custom 就无法检测重复项IEqualityComparer<X>。它只是看两者是否是相同的参考。
public class XComparer: IEqualityComparer<X>
{
    public bool Equals(X x1, X x2)
    {
        if (object.ReferenceEquals(x1, x2))
            return true;
        if (x1 == null || x2 == null)
            return false;
        return x1.ID.Equals(x2.ID);
    }
    public int GetHashCode(X x)
    {
        return x.ID.GetHashCode();
    }
}
Now you can use it in the overload of Union:
现在您可以在以下重载中使用它Union:
var comparer = new XComparer();
a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>(), new XComparer()); 

