假设我有两个类,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>
{
}
现在我想比较他们的泛型类型。我正在使用等式比较器来操作类型数组。比如Intersect,Subtract等。
我不想比较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();
以下Equality comparer始终返回false,无论我使用IsAssignableFrom
还是==
。这样做的正确方法是什么?
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;
}
}
答案 0 :(得分: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();
}
}