我有一個通用方法Compare,它T在簽名中接收兩個型別的輸入引數并比較它們的相等性。回傳一個布林值。對于“普通”c# .net 型別,邏輯相當簡單。
但是,泛型型別T也可以是List<U>(例如List<int> xList和List<int> yList),我想比較它們是否相等。我不知道U編譯時的型別,但可以動態獲取它,如下例所示。
我正在嘗試使用Enumerable.SequenceEqual<V>(), 進行串列比較,但此方法需要在編譯時知道 的型別。為了解決這個問題,我嘗試動態轉換Tto List<U>,但沒有成功。在運行時拋出錯誤(在代碼片段中指示)。
是否有一種優雅的方法來進行串列比較,如下面的嘗試,其中在編譯時不知道串列內部型別?我最接近答案的地方是:How to use local variable as a type?編譯器說“它是一個變數,但像型別一樣使用”,它似乎非常接近我需要的東西,但我無法將其用于成功的解決方案。
public bool Compare(T x, T y)
{
bool isEqual;
if (typeof(T).IsSubClassOfGenericBaseType(typeof(List<>)))
{
Type listElementType =
x.GetType().GetGenericArguments().Single();
Type specificListType = (typeof(List<>).MakeGenericType(listElementType));
dynamic xList = x.GetType().MakeGenericType(specificListType); // <-- Exception is thrown here.
dynamic yList = y.GetType().MakeGenericType(specificListType);
isEqual = Enumerable.SequenceEqual(xList, yList);
}
else
{
isEqual = EqualityComparer<T>.Default.Equals(x, y);
}
return isEqual;
}
的Type擴展方法IsSubClassOfGenericBaseType如下:
internal static bool IsSubClassOfGenericBaseType(
this Type type, Type genericBaseType)
{
if ( type.IsGenericType
&& type.GetGenericTypeDefinition() == genericBaseType)
{
return true;
}
if (type.BaseType != null)
{
return IsSubClassOfGenericBaseType(
type.BaseType, genericBaseType);
}
return false;
}
uj5u.com熱心網友回復:
這樣的事情對你有用嗎?
public static bool Compare(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;
if (x is null || y is null)
return false;
if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());
return x.Equals(y);
}
用法:
var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 1, 2, 3 };
var c = new List<int> { 1, 2, 4 };
var d = new List<bool>{ true, false, true };
var e = "string";
var f = new Collection<int> { 1, 2, 3 };
var g = new List<short> { 1, 2, 3 };
Console.WriteLine(Compare(a, b)); // True
Console.WriteLine(Compare(a, c)); // False
Console.WriteLine(Compare(a, d)); // False
Console.WriteLine(Compare(a, e)); // False
Console.WriteLine(Compare(a, f)); // True - might not be what you want,
Console.WriteLine(Compare(a, g)); // False
Console.ReadLine();
請注意,因為我正在使用SequenceEqual()(根據您的建議)List<int>,所以與等效的Collection<int>. 我認為這可能是您想要的,因為 aList<int> 是a Collection<int>,但只是您知道。
另請注意,您不應Compare()在代碼中呼叫該方法- 它可能會導致人們將其與IComparer.Compare().
請注意,此解決方案可能比僅執行以下操作要慢得多:
public static bool CompareDynamic<T>(T x, T y)
{
return typeof(T).IsSubClassOfGenericBaseType(typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}
這是由于所有的轉換(如果元素是值型別,則是裝箱)。如果元素很少,那么它并不重要,但對于可能有問題的大型集合。
為了完整起見,這里有一些基準代碼,比較了對相當大的int串列使用動態轉換的性能:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace Demo
{
[SimpleJob(RuntimeMoniker.Net50)]
public class Program
{
List<int> a = Enumerable.Range(1, 100_000).ToList();
List<int> b = Enumerable.Range(1, 100_000).ToList();
static void Main()
{
BenchmarkRunner.Run<Program>();
Console.ReadLine();
}
[Benchmark]
public void ViaCompareCast()
{
CompareCast(a, b);
}
[Benchmark]
public void ViaCompareDynamic()
{
CompareDynamic(a, b);
}
public static bool CompareCast(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;
if (x is null || y is null)
return false;
if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());
return x.Equals(y);
}
public static bool CompareDynamic<T>(T x, T y)
{
return IsSubClassOfGenericBaseType(typeof(T), typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}
static bool IsSubClassOfGenericBaseType(Type type, Type genericBaseType)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == genericBaseType)
return true;
if (type.BaseType != null)
return IsSubClassOfGenericBaseType(type.BaseType, genericBaseType);
return false;
}
}
}
The results (for a .net 5.0 release build) are as follows:
| Method | Mean | Error | StdDev | Median |
|------------------ |-----------:|---------:|----------:|-----------:|
| ViaCompareCast | 4,930.6 us | 96.79 us | 191.04 us | 4,832.1 us |
| ViaCompareDynamic | 667.6 us | 12.67 us | 28.07 us | 652.7 us |
As you can see, the version using dynamic is more than 70 times faster for this particular data set. So you pays your money and you makes your choice!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/311167.html
上一篇:將泛型型別傳遞給非泛型方法
