首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这种搜索方法中IComparable和IComparable<T>的区别

这种搜索方法中IComparable和IComparable<T>的区别
EN

Stack Overflow用户
提问于 2015-12-12 17:21:26
回答 4查看 840关注 0票数 4

我知道IComparableIComparable<T>在一般情况下有很大的区别,参见this,但是在这个搜索方法中,它不会有任何不同,或者会吗?

代码语言:javascript
复制
public static int Search<T>(List<T> a, T target) where T : IComparable
{
    for (int i = 0; i < a.Count; i++)
    {
        if (target.CompareTo(a[i]) == 0)
            return i;
    }
    return -1;
}

与之相比:

代码语言:javascript
复制
public static int Search<T>(List<T> a, T target) where T : IComparable<T>
{
    ...
}

这两种方法都能起作用,结果也是一样的吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-12-12 19:08:34

这两种方法都能起作用,结果也是一样的吗?

让我们看看编译器为这两种搜索方法发出了什么:

代码语言:javascript
复制
Search:
IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     // i
IL_0002:  br.s        IL_0025
IL_0004:  ldarga.s    01 
IL_0006:  ldarg.0     
IL_0007:  ldloc.0     // i
IL_0008:  callvirt    06 00 00 0A 
IL_000D:  box         03 00 00 1B <---- Notice this!
IL_0012:  constrained. 03 00 00 1B 
IL_0018:  callvirt    System.IComparable.CompareTo
IL_001D:  brtrue.s    IL_0021
IL_001F:  ldloc.0     // i
IL_0020:  ret         
IL_0021:  ldloc.0     // i
IL_0022:  ldc.i4.1    
IL_0023:  add         
IL_0024:  stloc.0     // i
IL_0025:  ldloc.0     // i
IL_0026:  ldarg.0     
IL_0027:  callvirt    08 00 00 0A 
IL_002C:  blt.s       IL_0004
IL_002E:  ldc.i4.m1   
IL_002F:  ret         

SearchGeneric:
IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     // i
IL_0002:  br.s        IL_0020
IL_0004:  ldarga.s    01 
IL_0006:  ldarg.0     
IL_0007:  ldloc.0     // i
IL_0008:  callvirt    06 00 00 0A 
IL_000D:  constrained. 03 00 00 1B 
IL_0013:  callvirt    09 00 00 0A 
IL_0018:  brtrue.s    IL_001C
IL_001A:  ldloc.0     // i
IL_001B:  ret         
IL_001C:  ldloc.0     // i
IL_001D:  ldc.i4.1    
IL_001E:  add         
IL_001F:  stloc.0     // i
IL_0020:  ldloc.0     // i
IL_0021:  ldarg.0     
IL_0022:  callvirt    08 00 00 0A 
IL_0027:  blt.s       IL_0004
IL_0029:  ldc.i4.m1   
IL_002A:  ret    

如果仔细观察,您会发现,主要的区别在于,Search中的每个调用在调用CompareTo之前都必须将值(这一点在box操作中是值得注意的),因为非泛型版本接受object类型。

让我们尝试使用https://msdn.microsoft.com/en-us/library/s1ax56ch.aspx来分析两者之间的性能差异。我将使用BenchmarkDotNet,它是一个有点(而且非常棒)的基准测试框架,它负责JITing、CPU热身等等。

测试:

代码语言:javascript
复制
[BenchmarkTask(platform: BenchmarkPlatform.X86)]
[BenchmarkTask(platform: BenchmarkPlatform.X64)]
public class Test
{
    private readonly List<int> list = Enumerable.Range(0, 1000000).ToList();

    [Benchmark]
    public void TestSearch()
    {
        Search(list, 999999);
    }

    [Benchmark]
    public void TestSearchGeneric()
    {
        SearchGeneric(list, 999999);
    }

    public static int Search<T>(List<T> a, T target) where T : IComparable
    {
        for (int i = 0; i < a.Count; i++)
        {
            if (target.CompareTo(a[i]) == 0)
                return i;
        }
        return -1;
    }
    public static int SearchGeneric<T>(List<T> a, T target) where T : IComparable<T>
    {
        for (int i = 0; i < a.Count; i++)
        {
            if (target.CompareTo(a[i]) == 0)
                return i;
        }
        return -1;
    }
}

结果:

代码语言:javascript
复制
***** Competition: Finish  *****

BenchmarkDotNet=v0.7.8.0
OS=Microsoft Windows NT 6.1.7601 Service Pack 1
Processor=Intel(R) Core(TM) i7-4600U CPU @ 2.10GHz, ProcessorCount=4
HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit
Type=Test  Mode=Throughput  Jit=HostJit  .NET=HostFramework


            Method | Platform |    AvrTime |    StdDev |   op/s |
------------------ |--------- |----------- |---------- |------- |
        TestSearch |      X64 | 35.8065 ms | 3.3439 ms |  27.93 |
 TestSearchGeneric |      X64 |  4.6427 ms | 0.3075 ms | 215.40 |
        TestSearch |      X86 | 26.4876 ms | 1.4776 ms |  37.75 |
 TestSearchGeneric |      X86 |  6.6500 ms | 0.1664 ms | 150.38 |

***** Competition: End *****

请注意,导致装箱操作的非泛型方法是,x86上的慢速超过4倍,而x64上的慢速超过8倍。这可能会对应用程序的性能产生影响。

我通常不会使用非泛型IComparable,它主要是为了向后兼容泛型之前的几天。请注意,另一个同样重要的因素是使用泛型获得的类型安全性。

票数 9
EN

Stack Overflow用户

发布于 2015-12-12 17:26:01

这是一个巨大的区别,第一种方法是无缘无故地装箱值类型。

票数 3
EN

Stack Overflow用户

发布于 2015-12-12 17:26:47

第一个(i.e. IComparable)实现的不是泛型类型,与父类使用的类型无关,但是第二个类型(即IComparable<T>)是类型安全的,您只能使用为父类指定的类型。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34242746

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档