我只是在看一个例子,在其中我看到了代码
return new IntPtr(handle);
在探索我们的代码之后,我发现我们已经使用了类似的模式,但在我们的代码中我们几乎有相同的东西:
return (IntPtr)handle;
这两种情况有区别吗?第二个是否会以任何方式“更好”,因为它不会分配新的内存,或者是否只是隐藏了相同的构造函数?
答案 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通过后这两者之间是否存在任何实际差异 - 但很可能没有(尽管我怀疑你在实践中注意到这两种方式,这是一种极端优化)。
在任何情况下,强制转换都比使用构造函数更惯用,所以我建议单独使用它。