[英]How to compare generic types based on constraints
假設我有兩個班,Foo和Bar。
public class Foo<TFirst, TSecond, TThird, T>
where TFirst : IReadOnlyList<T>
where TThird : IEnumerable<T>
{
}
public class Bar<TFirst, TSecond, TThird, T>
where TFirst : IReadOnlyList<T>
{
}
現在,我要比較它們的通用類型。 我正在使用相等比較器對類型數組進行操作。 如相交,相減等。
我不想比較Foo
和Bar
但我想比較它們的通用參數。
例如,如果兩個類型參數都具有相同的約束,則應將它們視為相等。 如果他們沒有約束,他們也應該被認為是平等的。
在上面的示例中,Foo的TFirst
應該被認為等於Bar的TFirst
。 以及TSecond
因為它們沒有約束。 TThrid
不相等,因為它們沒有相同的約束。
所以現在我有Foo和Bar類型。 我想分析它們的類型參數並將它們相互比較。
var fooType = typeof(Foo<,,,>);
var barType = typeof(Bar<,,,>);
var fooArgs = fooType.GetGenericArguments();
var barArgs = barType.GetGenericArguments();
var commonArgs = fooArgs.Intersect(barArgs, new GenericArgumentEqualityComparer()).ToArray();
var unknownBarArgs = barArgs.Except(commonArgs, new GenericArgumentEqualityComparer()).ToArray();
無論我使用IsAssignableFrom
或==
,跟隨Equality比較器始終返回false。 正確的方法是什么?
public class GenericArgumentEqualityComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y)
{
if (x == null || y == null) return false;
var xcons = x.GetGenericParameterConstraints();
var ycons = y.GetGenericParameterConstraints();
if(xcons.Length != ycons.Length) return false;
foreach (var cons in xcons)
{
if (ycons.All(cons2 => !cons.IsAssignableFrom(cons2)))
return false;
}
return true;
}
public int GetHashCode(Type obj)
{
// code runs on T4 for code generation. performance doesn't matter.
return 0;
}
}
意外的行為來自
cons.IsAssignableFrom
您不能嘗試將派生的開放泛型類型分配給派生基數,即使在分層結構上也可以以此為例
var ien = typeof(IEnumerable<string>);
var iread = typeof(IReadOnlyList<string>);
//isAssignable will be true
var isAssignable = ien.IsAssignableFrom(iread);
//here because IsAssignableFrom work from BaseType.IsAssignableFrom(DerviedType)
var isAssignableIEn = iread.IsAssignableFrom(ien);
還有這個
var ien = typeof(IEnumerable<>);
var iread = typeof(IReadOnlyList<>);
var isAssignable = ien.IsAssignableFrom(iread);
//here because IsAssignableFrom work from BaseType.IsAssignableFrom(DerviedType)
var isAssignableIEn = iread.IsAssignableFrom(ien);
這兩個分配檢查都將為false
這是預期的行為,因為默認情況下無法實例化開放的泛型類型,因此無法分配
要創建開放通用類型的實例,應使用Type.MakeGenericType
要解決您的問題,這可能對您有幫助
public class GenericArgumentEqualityComparer : IEqualityComparer<Type>
{
public bool Equals(Type x, Type y)
{
var xInterfacesTypes = x.GetInterfaces();
var yInterfacesTypes = y.GetInterfaces();
if (!xInterfacesTypes.Any()&&!yInterfacesTypes.Any() )
{
return true;
}
if ((!xInterfacesTypes.Any() && yInterfacesTypes.Any()) || xInterfacesTypes.Any() && !yInterfacesTypes.Any())
{
return false;
}
foreach (var xInterfacesType in xInterfacesTypes)
{
var iType = xInterfacesType.IsGenericType ? xInterfacesType.GetGenericTypeDefinition() :xInterfacesType;
var yType = yInterfacesTypes.Any(yI => yI.IsGenericType && yI.GetGenericTypeDefinition() == iType||yI.GetType()==xInterfacesType.GetType());
if (!yType)
{
return false;
}
}
return true;
}
public int GetHashCode(Type obj)
{
return obj.Name.GetHashCode();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.