假设我有一个无约束的泛型方法,适用于支持相等的所有类型。它执行成对等式检查,因此适用于 O(n 2 ):
public static int CountDuplicates<T>(IList<T> list)
{
/* ... */
}
我还有一个约束泛型方法,只适用于支持排序的类型。它从 O(n log n)中的列表排序开始,然后在一次通过中计算所有重复项:
public static int CountDuplicatesFast<T>(IList<T> list)
where T : IComparable<T>
{
/* ... */
}
因此,如果静态地知道列表的元素类型支持排序,则调用者可以选择调用fast方法。可能会发生调用者本身使用泛型IList<T>
,其中T是不受约束的,因此它是调用第一个(慢)方法的唯一选项。
现在,我希望第一个方法在运行时检查类型T
是否实际实现了接口IComparable<T>
,如果是,请调用fast方法:
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast(list);
}
else
{
/* use the slow algorithm */
}
}
问题是编译器拒绝调用CountDuplicatesFast(list)
:
错误CS0314:类型'T'不能用作泛型类型或方法'Program.CountDuplicatesFast&lt; T&gt;(System.Collections.Generic.IList&lt; T&gt;)'中的类型参数'T'。从'T'到'System.IComparable&lt; T&gt;'没有装箱转换或类型参数转换。
是否有可能说服编译器相信我,我知道自己在做什么,并跳过约束检查?
答案 0 :(得分:8)
您可以使用辅助类和dynamic
类型来跳过编译时检查:
sealed class CountDuplicatesFastCaller
{
public int Call<T>(IList<T> list) where T : IComparable<T>
{
return CountDuplicatesFast(list);
}
}
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof (IComparable<T>).IsAssignableFrom(typeof (T)))
{
return ((dynamic) new CountDuplicatesFastCaller()).Call(list);
}
else
{
/* use the slow algorithm */
}
}
由于DLR缓存机制,这应该比纯反射更快。
答案 1 :(得分:7)
以下是使用dynamic
:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast((dynamic)list);
}
或反思:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
var method = typeof(MyType).GetMethod("CountDuplicatesFast");
var generic = method.MakeGenericMethod(typeof(T));
return (int)generic.Invoke(null, new object[] { list });
}
我认为没有办法静态地做到这一点(即没有反思或dynamic
)。