2013-05-06 40 views
19

假设我有一个不受约束的泛型方法,它支持所有支持相等的类型。它执行成对的相等性检查等工作在为O(n 2 如何有条件地调用带约束的泛型方法?

public static int CountDuplicates<T>(IList<T> list) 
{ 
    /* ... */ 
} 

我也有只有具有类型支持排序工作的约束通用方法。它从Ø排序列表(N log n)的开始,然后计算所有副本中的一个通:

public static int CountDuplicatesFast<T>(IList<T> list) 
    where T : IComparable<T> 
{ 
    /* ... */ 
} 

因此,主叫方可以选择调用快速的方法,如果它是静态已知的是,列表中的元素类型支持排序。可能发生的情况是,调用者自己使用通用的IList<T>,其中T是无约束的,所以它是调用第一个(慢)方法的唯一选项。

现在,我想第一种方法在运行时检查类型T实际实现的接口IComparable<T>如果是这样,调用快速的方法:

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' 不能在通用类型或方法被用作类型参数 'T'“Program.CountDuplicatesFast <Ť>(System.Collections.Generic.IList <Ť>)'。没有从'T'到'System.IComparable <T>'的装箱转换或类型参数转换。

是否有可能说服编译器相信我,我知道我在做什么,并跳过约束检查?

+1

您是否尝试过使用Cast? ()。ToList());' – Nevyn 2013-05-06 19:31:18

+0

@Nevyn产生的类型'System.IComparable '不能用作泛型类型中的类型参数'T',或者不能用作类型'System.IComparable ' 'UserQuery.MyType.CountDuplicatesFast (System.Collections.Generic.IList )'。没有从'System.IComparable '到'System.IComparable >'的隐式引用转换。“ – 2013-05-06 19:36:40

+0

有趣。几乎是正确的轨道,但完全是错误的执行。我想我需要写出一个测试程序并尝试一些不同的东西。我认为演员也许可以做到这一点......但我不知道该怎么做......哦,第一次猜测它并不太遥远:-) – Nevyn 2013-05-06 19:40:37

回答

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 )。

+3

不错!我没有想到要抛出这个论点。我认为我的方法仅在极少数情况下需要,当存在类型参数但没有值参数时。 – 2013-05-06 19:39:49

+0

@VladimirReshetnikov呃..即使那样,这会有帮助吗?除非辅助类添加了一个虚拟参数来让这个类型被推断,否则我不会看到它。 – 2013-05-06 21:57:37

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缓存机制纯反射更快。

相关问题