IntPtr演员与新演员

时间:2009-08-06 05:31:15

标签: c# intptr

我只是在看一个例子,在其中我看到了代码

return new IntPtr(handle);

在探索我们的代码之后,我发现我们已经使用了类似的模式,但在我们的代码中我们几乎有相同的东西:

return (IntPtr)handle;

这两种情况有区别吗?第二个是否会以任何方式“更好”,因为它不会分配新的内存,或者是否只是隐藏了相同的构造函数?

4 个答案:

答案 0 :(得分:8)

在你的例子中,我猜句柄是一个整数值? IntPtr声明从Int32(int)和Int64(long)的显式转换,它只调用相同的构造函数:

public static explicit operator IntPtr(int value)
{
    return new IntPtr(value);
}

除了可能的可读性问题之外,实际上没有区别。

答案 1 :(得分:5)

Reflector说演员正在调用引擎盖下的构造函数:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct IntPtr : ISerializable
{
    ...

    [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
    public static explicit operator IntPtr(int value)
    {
        return new IntPtr(value);
    }

}

答案 2 :(得分:3)

所以这个线程都是谈话而没有数字,所以让我们谈谈指标。我运行了一些测试代码,以使用Visual Studio 2010和

获得一些性能指标

我通过计算10个测试运行中的任一方法的平均时间来获得这些指标,其中每个在Debug然后发布模式下进行1000万次迭代(未优化然后优化):

(调试) 铸造方法:~32毫秒 分配方法:~26 ms

(释放) 铸造方法:~20 ms 分配方法:~22 ms

有趣的是,仅使用gcnew将这些指标与托管C ++的类似代码进行比较,结果会有很大不同。

再次设置相同。除了比较铸造方法:“IntPtr ^ ptr =(IntPtr)i;” vs分配方法:“IntPtr ^ ptr =(IntPtr)i;”。

(调试) 铸造方法:~91ms 分配方法:~127ms

(释放) 铸造方法:~22ms 分配方法:~124ms

现在,如果你正在轻描淡写地说好,为什么C#比托管C ++快得多,答案是不是。使用IntPtr的最有效方法是作为值类型而不是对值类型的引用。例如像“IntPtr ptr =(IntPtr)i;”。这将为您提供~24ms(Debug more)或(~22 Release模式)。看看编译器如何优化它以获得22ms而不是90ms。

在C#中的结论,除非你正在寻找真正非常严格的代码,否则无关紧要。我认为我在Release中的代码实际上是在优化演员,因为评论演员给出了相同的~22ms。但是在大多数情况下,编译器会在C#中重新使用这个,至少VS 2010。但是,在托管C ++ / CLI中,如果您正在查看具有最小性能约束的代码,那么请注意。编译器不会自动优化对cast方法的gcnew分配,而且几乎快6倍......我实际上遇到了C ++ / CLI中的这个特殊问题,这导致我在处理一些实时音频时发布在这个线程上处理。我的代码(C#):(我的托管C ++代码非常相似,除了我自己编写Average()并使用控制台输出而不是消息框。)

    static void Main()
    {
        List<int> castTimings = new List<int>();
        List<int> allocTimings = new List<int>();

        for (int i = 0; i < TEST_RUNS; ++i)
        {
            castTimings.Add(RunCastMethod().Milliseconds);
            allocTimings.Add(RunAllocationMethod().Milliseconds);
        }

        MessageBox.Show(string.Format("Casting Method took: {0}ms", castTimings.Average() ));
        MessageBox.Show(string.Format("Allocation Method took: {0}ms", allocTimings.Average() ));
    }

    private static TimeSpan RunAllocationMethod() {
        DateTime start = DateTime.Now;

        for (int i = 0; i < TEST_ITERATIONS; ++i)
        {
            IntPtr ptr = new IntPtr(i);
        }

        return ( DateTime.Now - start );
    }

    private static TimeSpan RunCastMethod()
    {
        DateTime start = DateTime.Now;

        for (int i = 0; i < TEST_ITERATIONS; ++i)
        {
            IntPtr ptr = (IntPtr) i;
        }

        return (DateTime.Now - start);
    }

答案 3 :(得分:2)

由于IntPtr是值类型,因此使用new不会分配任何内存。

从技术上讲,调用仍然编译为不同的IL - 一个实际调用构造函数,另一个调用显式转换运算符。我不确定在JIT通过后这两者之间是否存在任何实际差异 - 但很可能没有(尽管我怀疑你在实践中注意到这两种方式,这是一种极端优化)。

在任何情况下,强制转换都比使用构造函数更惯用,所以我建议单独使用它。