咨询区
Prasad Kanaparthi:
我在使用 Union
和 Concat
上有一个困惑,从字面上理解:一个是并集,一个是连接,下面的例子就是我对这两个扩展方法的理解。
static void Main(string[] args){var a1 = (new[] { 1, 2 }).Union(new[] { 1, 2 });var a2 = (new[] { 1, 2 }).Concat(new[] { 1, 2 });var a3 = (new[] { "1", "2" }).Union(new[] { "1", "2" });var a4 = (new[] { "1", "2" }).Concat(new[] { "1", "2" });Console.WriteLine($"a1={string.Join(",", a1)}");Console.WriteLine($"a2={string.Join(",", a2)}");Console.WriteLine("---------------------------");Console.WriteLine($"a3={string.Join(",", a3)}");Console.WriteLine($"a4={string.Join(",", a4)}");Console.ReadLine();}
现在问题来了,为什么我切换到 List<T>
上却是不同的表现呢?参考下面的代码。
class Program{static void Main(string[] args){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>());var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>());Console.WriteLine($"a5.Count={a5.Count()}, a6.Count={a6.Count()}");Console.ReadLine();}}class X{public int ID { get; set; }}class X1 : X{public int ID1 { get; set; }}class X2 : X{public int ID2 { get; set; }}
为什么结果是两个 4 呢 ?给个建议吧 ????
回答区
Sergey Berezovskiy:
Union 返回的是 Distinct
的值,默认情况下会比较这些 items 的引用,你的 items 其实都是不同的引用值,即使你转成基类 X
,引用值也不会被改变。
如果你重写了 item 的 Equals
和 GetHashCode
的话,那么 items 之间的比较就不会按照默认的引用比较了,参考如下代码。
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();}
}
可以再次运行一下,你将会看到 Union
和 Concat
不同的表现啦。
点评区
这道题感觉可以做面试题,挺有意思的,用了一个障眼法,以为都转成基类 X
就可以瞒过 CLR 了,有点自作聪明哈????,对象从生下来的那一刻起,他就有专属的内存地址啦。。。(不讨论GC压缩????)