首页 > 解决方案 > 编译器迫使我在“...”上实现终结器或析构函数

问题描述

在 VS 2017 中分析代码时,会显示一条错误消息,告知“在 '...' 上实现终结器或析构函数”。问题是为什么?

如果我以这种方式实现析构函数:

    ~RawPrinterHelper()
    {

    }

显示另一条消息:

'RawPrinterHelper' implements a finalizer that only calls conditionally emitted methods or the base type finalizer. Remove the finalizer or ensure that it is only conditionally compiled into the assembly. If this violation occurs against a finalizer that is entirely wrapped in a conditionally-emitted block of code, suppress this message. 

如何解决这个问题?该类还实现了 IDisposable 接口。

编辑:

这是生成的完整类:

public sealed class RawPrinterHelper : IDisposable
{
    private NativeMethods.DOCINFOA _di = new NativeMethods.DOCINFOA();
    private IntPtr _hPrinter = IntPtr.Zero;

    public bool PrinterIsOpened { get; private set; }

    public bool OpenPrinter(string printerName)
    {
        if (!this.PrinterIsOpened)
        {
            if (NativeMethods.OpenPrinter(printerName, out _hPrinter, IntPtr.Zero))
                this.PrinterIsOpened = true;
        }

        return this.PrinterIsOpened;
    }

    public void ClosePrinter()
    {
        if (this.PrinterIsOpened)
        {
            NativeMethods.ClosePrinter(_hPrinter);

            this.PrinterIsOpened = false;
        }
    }

    public bool CreateDocument(string name)
    {
        if (this.PrinterIsOpened)
        {
            _di.pDocName = name;
            _di.pDataType = "RAW";
            if (NativeMethods.StartDocPrinter(_hPrinter, 1, _di))
            {
                if (NativeMethods.StartPagePrinter(_hPrinter))
                {
                    return true;
                }
            }
        }

        return false;
    }

    public void CloseDocument()
    {
        NativeMethods.EndPagePrinter(_hPrinter);
        NativeMethods.EndDocPrinter(_hPrinter);
    }

    public bool SendStringToPrinter(string text)
    {
        if (this.PrinterIsOpened)
        {

            IntPtr pBytes = Marshal.StringToCoTaskMemAnsi(text);
            int dwCount = text.Length;
            int dwWritten = 0;

            try
            {
                return NativeMethods.WritePrinter(_hPrinter, pBytes, dwCount, out dwWritten);
            }
            finally
            {
                Marshal.FreeCoTaskMem(pBytes);
            }
        }

        return false;
    }

    public bool SendBytesToPrinter(byte[] bytes)
    {
        if (this.PrinterIsOpened)
        {
            IntPtr pBytes = Marshal.AllocHGlobal(bytes.Length);
            Marshal.Copy(bytes, 0, pBytes, bytes.Length);
            int dwCount = bytes.Length;
            int dwWritten = 0;

            try
            {
                return NativeMethods.WritePrinter(_hPrinter, pBytes, dwCount, out dwWritten);
            }
            finally
            {
                Marshal.FreeHGlobal(pBytes);
            }
        }

        return false;
    }

    public byte[] ReceiveBytesFromPrinter()
    {
        if (this.PrinterIsOpened)
        {
            int maxRead = 256;
            byte[] bytes = new byte[256];
            IntPtr pBytes = Marshal.AllocHGlobal(bytes.Length);

            int nBytesRead = 0;

            try
            {
                //Read Data                
                if (NativeMethods.ReadPrinter(_hPrinter, pBytes, maxRead, out nBytesRead))
                    return bytes;
            }
            finally
            {
                Marshal.FreeHGlobal(pBytes);
            }
        }

        return null;
    }

    // SendBytesToPrinter()
    // When the function is given a printer name and an unmanaged array
    // of bytes, the function sends those bytes to the print queue.
    // Returns true on success, false on failure.
    public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
    {
        Int32 dwError = 0, dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        NativeMethods.DOCINFOA di = new NativeMethods.DOCINFOA();
        bool bSuccess = false; // Assume failure unless you specifically succeed.

        di.pDocName = "RAW Document";
        // Win7
        di.pDataType = "RAW";

        // Win8+
        // di.pDataType = "XPS_PASS";

        // Open the printer.
        if (NativeMethods.OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
        {
            // Start a document.
            if (NativeMethods.StartDocPrinter(hPrinter, 1, di))
            {
                // Start a page.
                if (NativeMethods.StartPagePrinter(hPrinter))
                {
                    // Write your bytes.
                    bSuccess = NativeMethods.WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                    NativeMethods.EndPagePrinter(hPrinter);
                }
                NativeMethods.EndDocPrinter(hPrinter);
            }
            NativeMethods.ClosePrinter(hPrinter);
        }
        // If you did not succeed, GetLastError may give more information
        // about why not.
        if (bSuccess == false)
        {
            dwError = Marshal.GetLastWin32Error();
        }
        return bSuccess;
    }

    public static bool SendFileToPrinter(string szPrinterName, string szFileName)
    {
        // Open the file.
        FileStream fs = new FileStream(szFileName, FileMode.Open);
        // Create a BinaryReader on the file.
        BinaryReader br = new BinaryReader(fs);
        // Dim an array of bytes big enough to hold the file's contents.
        Byte[] bytes = new Byte[fs.Length];
        bool bSuccess = false;
        // Your unmanaged pointer.
        IntPtr pUnmanagedBytes = new IntPtr(0);
        int nLength;

        nLength = Convert.ToInt32(fs.Length);
        // Read the contents of the file into the array.
        bytes = br.ReadBytes(nLength);
        // Allocate some unmanaged memory for those bytes.
        pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
        // Copy the managed byte array into the unmanaged array.
        Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
        // Send the unmanaged bytes to the printer.
        bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
        // Free the unmanaged memory that you allocated earlier.
        Marshal.FreeCoTaskMem(pUnmanagedBytes);
        fs.Close();
        fs = null;
        return bSuccess;
    }
    public static bool SendStringToPrinter(string szPrinterName, string szString)
    {
        IntPtr pBytes;
        Int32 dwCount;
        // How many characters are in the string?
        dwCount = szString.Length;
        // Assume that the printer is expecting ANSI text, and then convert
        // the string to ANSI text.
        pBytes = Marshal.StringToCoTaskMemAnsi(szString);
        // Send the converted ANSI string to the printer.
        SendBytesToPrinter(szPrinterName, pBytes, dwCount);
        Marshal.FreeCoTaskMem(pBytes);
        return true;
    }

    public void Dispose()
    {

    }

    ~RawPrinterHelper()
    {
        Dispose();
    }
}

标签: c#destructordisposefinalizer

解决方案


需要终结器来处理非托管资源。通常你不需要实现终结器,除非你持有非托管资源。

你的终结器是空的,这会导致问题:终结器是一个特定的方法,编译器希望你做一些有意义的事情并遵守规范(即必须真正释放非托管资源)。空的终结器对编译器来说是一个危险信号,因为您可能忘记实现它。由于我们正在处理无法自动释放的资源,因此在这种情况下编译器是额外安全的。

如果您的类实现IDisposable了,您可以按照MSDNIDisposable此处描述的方式实现该模式。


推荐阅读