我认为以前没有问过这个问题.我IDisposable对在密封类上实现的最佳方法感到困惑- 特别是一个不从基类继承的密封类.(也就是说,这是一个"纯密封的类",这是我的术语.)
也许你们有些人同意我的观点,因为实施指南IDisposable非常混乱.也就是说,我想知道我打算实施的方式IDisposable是充分和安全的.
我正在做一些P/Invoke代码,分配一个IntPtr通过Marshal.AllocHGlobal,自然,我想干净地处理我创建的非托管内存.所以我在考虑这样的事情
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public sealed class MemBlock : IDisposable
{
IntPtr ptr;
int length;
MemBlock(int size)
{
ptr = Marshal.AllocHGlobal(size);
length = size;
}
public void Dispose()
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
GC.SuppressFinalize(this);
}
}
~MemBlock()
{
Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
我假设因为MemBlock完全是密封的,并且永远不会从另一个实现a的类中派生出来virtual protected Dispose(bool disposing).
那么,终结者是否必须?欢迎所有的想法.
这更像是一个'奇怪的原因',而不是一个特定的问题,但请看下面的代码
static void Main(string[] args)
{
int val = 10;
Console.WriteLine("val is {0}", val); // (1)
Console.WriteLine("val is {0}", val.ToString()); //(2)
}
Run Code Online (Sandbox Code Playgroud)
在情况(1)中输出以下IL
IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
IL_0004: ldstr "val is {0}"
IL_0009: ldloc.0
IL_000a: box [mscorlib]System.Int32
IL_000f: call void [mscorlib]System.Console::WriteLine(string,
object)
Run Code Online (Sandbox Code Playgroud)
在我明确调用toString方法的情况下(2)我得到了
IL_0014: nop
IL_0015: ldstr "val is {0}"
IL_001a: ldloca.s val
IL_001c: call instance string [mscorlib]System.Int32::ToString()
IL_0021: call void [mscorlib]System.Console::WriteLine(string,
object)
Run Code Online (Sandbox Code Playgroud)
所以在case(1)中,即使int重写toString,也会将值类型装箱并调用toString方法,这可能会调用vtable覆盖
所以结果完全相同,但显式的toString避免了装箱操作
谁知道为什么?
=编辑=
确定要清楚,令我感到困惑的是,我开始假设即使int派生自System.ValueType,而System.ValueType又派生自System.Object,因为它包含toString,GetHashCode等.
所以在我的天真view(可能来自C++),如果我重写从System.Object派生的方法,那么就不需要强制转换为System.Object(因此将值类型框),因为存在overriden方法,编译器将自动引用vtable条目对于类型.
我也假设调用Console.WriteLine()隐式调用int.toString所以也许这就是我出错的地方.希望有道理
好的 - 全部排序.谢谢大家直截了当.所有这些都与我的糟糕假设有关,即Console.WriteLine正在进行隐式字符串转换.不要问我为什么这么想 - 看起来很明显现在错误:)
我经常想知道c#中是否真的发生了以下情况
如果我有一个结构但我没有显式覆盖从对象派生的任何方法,如ToString(),GetHashCode()等,那么如果我声明我的struct类的本地实例并调用'ToString()'它,我的struct会被装箱,即CLR会将它隐式转换为堆上的对象,然后调用ToString()吗?或者它是否足够聪明地知道该结构没有实现并忽略它?
即
public struct Vector2D
{
public float m_x;
public float m_y;
...... etc
}
void SomeFunc()
{
Vector2D aVec = new Vector2D();
Console.WriteLine(aVec.ToString()); // <-- does aVec get boxed here?
.....
}
Run Code Online (Sandbox Code Playgroud)
==编辑 - 更新== Mehrdad 与MSDN的链接,虽然有用但让我感到困惑.我会引用,看看是否有人可以为我取消这个
当callvirt方法指令以约束thisType作为前缀时,指令执行如下:
如果thisType是引用类型(而不是值类型),则取消引用ptr并将其作为'this'指针传递给方法的callvirt.
如果thisType是一个值类型而thisType实现了方法,那么ptr将被未修改地传递为调用方法指令的'this'指针,用于通过thisType实现方法.
如果thisType是一个值类型而thisType没有实现方法,则ptr被解除引用,装箱,并作为'this'指针传递给callvirt方法指令.
那么这是否意味着如果我没有在我的结构类型上明确地实现ToString(),它将落入最后一个案例并被装箱?或者我在某处误解了它?