Pio*_*lin 20 .net c# generics clr constraints
假设我有一个无约束的泛型方法,适用于支持相等的所有类型.它执行成对等式检查,因此适用于O(n 2):
public static int CountDuplicates<T>(IList<T> list)
{
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
我还有一个约束泛型方法,只适用于支持排序的类型.它从O(n log n)中的列表排序开始,然后在一次传递中计算所有重复项:
public static int CountDuplicatesFast<T>(IList<T> list)
where T : IComparable<T>
{
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
因此,如果静态地知道列表的元素类型支持排序,则调用者可以选择调用快速方法.可能会发生调用者本身使用泛型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 */
}
}
Run Code Online (Sandbox Code Playgroud)
问题是编译器拒绝调用CountDuplicatesFast(list)
:
错误CS0314:类型'T'不能用作泛型类型或方法'Program.CountDuplicatesFast <T>(System.Collections.Generic.IList <T>)'中的类型参数'T'.从'T'到'System.IComparable <T>'没有装箱转换或类型参数转换.
是否有可能说服编译器相信我,我知道我在做什么,并跳过约束检查?
您可以使用帮助程序类和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 */
}
}
Run Code Online (Sandbox Code Playgroud)
由于DLR缓存机制,这应该比纯反射更快.
以下是使用以下方法的方法dynamic
:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast((dynamic)list);
}
Run Code Online (Sandbox Code Playgroud)
或者用反思:
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 });
}
Run Code Online (Sandbox Code Playgroud)
我不认为有办法静态地做这个(即没有反思或dynamic
).
归档时间: |
|
查看次数: |
1246 次 |
最近记录: |