3

我只是在看一个例子,在里面我看到了代码

return new IntPtr(handle);

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

return (IntPtr)handle;

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

4

4 回答 4

8

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

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

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

于 2009-08-06T05:36:21.510 回答
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);
    }

}
于 2009-08-06T05:37:02.900 回答
4

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

我通过计算任何一种方法在 10 次测试运行中的平均时间得到这些指标,每个测试运行 1000 万次迭代,然后在 Debug 然后 Release 模式(非优化然后优化):

(调试)铸造方法:~32 ms 分配方法:~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(调试更多)或(〜22发布模式)。看看编译器如何在上面优化它以获得 22 毫秒而不是 90 毫秒。

C# 中的结论,除非您正在查看非常非常紧凑的代码,否则没关系。我认为我在 Release 中的代码实际上是在优化演员阵容,因为注释掉演员阵容给出了相同的 ~22 毫秒。但在大多数情况下,编译器在 C# 中支持这一点,至少 VS 2010 支持。但是,在托管 C++/CLI 中,如果您正在查看具有最小性能限制的代码,那么请注意。编译器不会自动优化对转换方法的 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);
    }
于 2010-12-12T09:08:26.830 回答
2

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

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

在任何情况下,强制转换比使用构造函数更惯用,所以我建议仅出于这个原因就使用它。

于 2009-08-06T05:36:35.193 回答