编译器强迫我在'...'上实现终结器或析构函数

时间:2019-01-15 15:55:34

标签: c# destructor dispose finalizer

在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();
    }
}

1 个答案:

答案 0 :(得分:0)

需要终结器来处置非托管资源。通常,除非您持有非托管资源,否则无需实现终结器。

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

如果您的类实现IDisposable,则可以实现MSDN所述的IDisposable模式。