Search code examples
c#.netc++-clidispose

CLI C++ derive from C# disposable class


I am trying to create a CLI C++ class that derives from HashAlgorithm. HashAlgorithm has a a virtual Dispose(bool) method. I cannot override the Dispose method because I get a compile error stating dispose is a reserved keyword. From what I read online just adding a finalizer and dtor and the compiler will take care of everything else. I did this and the code compiles. When I try to use I get the error below:

System.TypeLoadException: Declaration referenced in a method implementation cannot be a final method

When I look at the code the compiler generated I see it puts this sealed keyword on the method which appears to be the source of the problem. The Dispose method is not really needed at all because it already exists on the base class. Any idea on how to get around this.

public sealed override void Dispose()

Solution

  • As you noted, in C++/CLI we implement ~ClassName and !ClassName, and the C++/CLI compiler writes Dispose(void) and Dispose(bool) for us.

    I tried deriving from HashAlgorithm, and I was able to get both the dispose & finalize to work. Perhaps there's a subtle difference in how you have some of the methods declared.

    Here's my test code:

    public ref class CppDispose : HashAlgorithm
    {
    private:
        ~CppDispose() { Debug::WriteLine("~CppDispose"); }
        !CppDispose() { Debug::WriteLine("!CppDispose"); }
    
    protected:
        virtual void HashCore(array<Byte>^ aray, int ibStart, int cbSize) override { }
        virtual array<Byte>^ HashFinal() override { return nullptr; }
    
    public:
        virtual void Initialize() override { }
    };
    
    int main(array<System::String ^> ^args)
    {
        {
            CppDispose foo;
    
            Debug::WriteLine("Disposing: ");
        }
    
        {
            CppDispose^ foo = gcnew CppDispose();
    
            Debug::WriteLine("Finalizing: ");
            foo = nullptr;
            GC::Collect();
        }
    
        return 0;
    }
    

    Output:

    Disposing: 
    ~CppDispose
    Finalizing: 
    !CppDispose
    

    So that you can see what's going on behind the scenes, here's the methods that the C++/CLI compiler wrote for us, decompiled to C# syntax. In this case, the parent class has Dispose(void) implemented, so it's not reimplemented here.

    [HandleProcessCorruptedStateExceptions]
    protected override void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1)
    {
        if (flag1)
        {
            try
            {
                this.~CppDispose();
            }
            finally
            {
                base.Dispose(true);
            }
        }
        else
        {
            try
            {
                this.!CppDispose();
            }
            finally
            {
                base.Dispose(false);
            }
        }
    }
    
    protected override void Finalize()
    {
        this.Dispose(false);
    }