Implementing IDisposable
-
Hi there! I am currently currently working .net classes that implement IDisposable following the msdn-guidelines, but I have a problem I hope you can help me with: Let's say these are my classes:
public __gc class B : public IDisposable { public: // Destructor calls Dispose(bool) ~B() { Dispose(false); } // Implements interface virtual void Dispose() { Dispose(true); GC::SuppressFinalize(this); } // this is the workhorse, it handles manual and finalizer // disposing differently as recommended by MS virtual void Dispose(bool arg) { /* whatever */ } }; public __gc class D : public B { public: // overrides Dispose(bool), but ultimatly calls B::Dispose(bool) virtual void Dispose(bool arg) { /* whatever */ B::Dispose(arg); } };
Looks nice, but does not work :( I can't do something like that:D* d = new D(); d->Dispose();
as the hide-by-name convention does not allow that. In native C++ I could use a using declaration:public __gc class D : public B { using B::Dispose; /*...*/ };
and everything was fine. However, this is not allowed in .net. Nevertheless this implementation of IDispose is used throughout the framework. How did MS do this? Did I miss something? Is it only possible in C#? Thanks in advance. - Andre (VizOne) Loker -
Hi there! I am currently currently working .net classes that implement IDisposable following the msdn-guidelines, but I have a problem I hope you can help me with: Let's say these are my classes:
public __gc class B : public IDisposable { public: // Destructor calls Dispose(bool) ~B() { Dispose(false); } // Implements interface virtual void Dispose() { Dispose(true); GC::SuppressFinalize(this); } // this is the workhorse, it handles manual and finalizer // disposing differently as recommended by MS virtual void Dispose(bool arg) { /* whatever */ } }; public __gc class D : public B { public: // overrides Dispose(bool), but ultimatly calls B::Dispose(bool) virtual void Dispose(bool arg) { /* whatever */ B::Dispose(arg); } };
Looks nice, but does not work :( I can't do something like that:D* d = new D(); d->Dispose();
as the hide-by-name convention does not allow that. In native C++ I could use a using declaration:public __gc class D : public B { using B::Dispose; /*...*/ };
and everything was fine. However, this is not allowed in .net. Nevertheless this implementation of IDispose is used throughout the framework. How did MS do this? Did I miss something? Is it only possible in C#? Thanks in advance. - Andre (VizOne) LokerTry this template:
public __gc class Hello : public System::IDisposable
{
public:
Hello(void)
{
}virtual ~Hello(void) { Dispose(false); } //////////////////////////////////////////////////////////////////////////// // The System::IDisposable interface implementations void Dispose() { Dispose(true); }
protected:
void Dispose(bool disposing)
{
// Normally clean up here....if (disposing) { System::GC::SuppressFinalize(this); } }
};
Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
-
Try this template:
public __gc class Hello : public System::IDisposable
{
public:
Hello(void)
{
}virtual ~Hello(void) { Dispose(false); } //////////////////////////////////////////////////////////////////////////// // The System::IDisposable interface implementations void Dispose() { Dispose(true); }
protected:
void Dispose(bool disposing)
{
// Normally clean up here....if (disposing) { System::GC::SuppressFinalize(this); } }
};
Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
This was what I have done. However, I can't call Dipose() on an object of the derived class because it is hidden-by-name. I guess this template is only implemantable in C#, so I simply renamed Dispose(bool) to InternalDispose(bool), which works fine for me. Nevertheless thanks for your answer. - Andre
-
This was what I have done. However, I can't call Dipose() on an object of the derived class because it is hidden-by-name. I guess this template is only implemantable in C#, so I simply renamed Dispose(bool) to InternalDispose(bool), which works fine for me. Nevertheless thanks for your answer. - Andre
The Dispose(Boolean) has nothing to do with .NET. The interface IDisposable only defines Dispose(), so you are doing anything wrong here. The Dispose(Boolean) is defined as either private or protected, so external classes are not supposed to access it. See the doc for IDisposable, there is an MC++ example given there to confirm your approach. Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
-
The Dispose(Boolean) has nothing to do with .NET. The interface IDisposable only defines Dispose(), so you are doing anything wrong here. The Dispose(Boolean) is defined as either private or protected, so external classes are not supposed to access it. See the doc for IDisposable, there is an MC++ example given there to confirm your approach. Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
Yes, I *do* know. And I don't want to access Dispose(bool), but Dispose(). I give you an example of what I mean:
public __gc class B : public IDisposable { public: virtual ~B() { Dispose(false); } virtual void Dispose() { Dispose(true); } protected: virtual void Dispose(bool arg) { /* Clean up */ } }; public __gc class D : public B { protected: virtual void Dispose(bool arg) { /* Clean up */ // call base classes implementation B::Dispose(arg); } }; int _tmain(void) { D * d = new D(); d->Dispose(); return 0; }
This is implemented as suggested in MSDN, isn't it? However, it does not work. d->Dispose() generates a C2660 saying that Dispose does not accept 0 parameters. This error is obviously caused by the fact that Dispose() is hidden-by-name. I could use d->B::Dispose() but this looks ugly to me, so I renamed Dispose(bool) to InternalDispose(bool). Hope I could explain what I meant. - Andre -
Yes, I *do* know. And I don't want to access Dispose(bool), but Dispose(). I give you an example of what I mean:
public __gc class B : public IDisposable { public: virtual ~B() { Dispose(false); } virtual void Dispose() { Dispose(true); } protected: virtual void Dispose(bool arg) { /* Clean up */ } }; public __gc class D : public B { protected: virtual void Dispose(bool arg) { /* Clean up */ // call base classes implementation B::Dispose(arg); } }; int _tmain(void) { D * d = new D(); d->Dispose(); return 0; }
This is implemented as suggested in MSDN, isn't it? However, it does not work. d->Dispose() generates a C2660 saying that Dispose does not accept 0 parameters. This error is obviously caused by the fact that Dispose() is hidden-by-name. I could use d->B::Dispose() but this looks ugly to me, so I renamed Dispose(bool) to InternalDispose(bool). Hope I could explain what I meant. - AndreVizOne wrote: Hope I could explain what I meant. Yeah, but you are missing the point main here. VizOne wrote: I could use d->B::Dispose() but this looks ugly to me, so I renamed Dispose(bool) to InternalDispose(bool). Add some output to the D::Dispose or D::InternalDispose to see if it is being called! A better picture is cast the D pointer to IDisposable, it will compile, but similar to the above you end up calling B::Dispose, it is similar to your d->B::Dispose() syntax.
int _tmain(void)
{
D * d = new D();
__try_cast(d)->Dispose();
return 0;
}The best way is to implement the same interface in D, since you will not get the expected result by renaming. Also, you trying to convert the IDisposable::Dispose() to virtual, it will compile but will not act as virtual method. Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
-
VizOne wrote: Hope I could explain what I meant. Yeah, but you are missing the point main here. VizOne wrote: I could use d->B::Dispose() but this looks ugly to me, so I renamed Dispose(bool) to InternalDispose(bool). Add some output to the D::Dispose or D::InternalDispose to see if it is being called! A better picture is cast the D pointer to IDisposable, it will compile, but similar to the above you end up calling B::Dispose, it is similar to your d->B::Dispose() syntax.
int _tmain(void)
{
D * d = new D();
__try_cast(d)->Dispose();
return 0;
}The best way is to implement the same interface in D, since you will not get the expected result by renaming. Also, you trying to convert the IDisposable::Dispose() to virtual, it will compile but will not act as virtual method. Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.
Paul Selormey wrote: Also, you trying to convert the IDisposable::Dispose() to virtual, it will compile but will not act as virtual method Well I am sure it *does* act as a virtual method. Excerpt from MSDN doc on managed c++: "The following features are supported for __gc interfaces: All methods of an interface are implicitly pure virtual. Neither the keyword virtual nor the suffix =0 is required on an interface method declaration, although both are allowed" Here is a small test in which I have included everything I mentioned so far. It works perfectly for me:
public __gc class B : public IDisposable { public: virtual ~B() { Console::WriteLine("B::~B()"); InternalDispose(false); } virtual void Dispose() { Console::WriteLine("B::Dispose()"); InternalDispose(true); } protected: // renaming this function to InternalDispose solved my problem virtual void InternalDispose(bool arg) { Console::WriteLine("B::InternalDispose(bool)"); /* Clean up */ } }; public __gc class D : public B { public: // just to show that the function *is* virtual void Dispose() { Console::WriteLine("D::Dispose()"); B::Dispose(); } protected: void InternalDispose(bool arg) { Console::WriteLine("D::InternalDispose(bool)"); /* Clean up */ // call base classes implementation B::InternalDispose(arg); } }; int _tmain(void) { B * b = new D(); b->Dispose(); // as virtual as can be *g* }
The output is (as expected) D::Dispose() B::Dispose() D::InternalDispose(bool) B::InternalDispose(bool) Of course, in my final version I will mark B::Dispose() as __sealed and throw away D::Dispose() - Andre -
Paul Selormey wrote: Also, you trying to convert the IDisposable::Dispose() to virtual, it will compile but will not act as virtual method Well I am sure it *does* act as a virtual method. Excerpt from MSDN doc on managed c++: "The following features are supported for __gc interfaces: All methods of an interface are implicitly pure virtual. Neither the keyword virtual nor the suffix =0 is required on an interface method declaration, although both are allowed" Here is a small test in which I have included everything I mentioned so far. It works perfectly for me:
public __gc class B : public IDisposable { public: virtual ~B() { Console::WriteLine("B::~B()"); InternalDispose(false); } virtual void Dispose() { Console::WriteLine("B::Dispose()"); InternalDispose(true); } protected: // renaming this function to InternalDispose solved my problem virtual void InternalDispose(bool arg) { Console::WriteLine("B::InternalDispose(bool)"); /* Clean up */ } }; public __gc class D : public B { public: // just to show that the function *is* virtual void Dispose() { Console::WriteLine("D::Dispose()"); B::Dispose(); } protected: void InternalDispose(bool arg) { Console::WriteLine("D::InternalDispose(bool)"); /* Clean up */ // call base classes implementation B::InternalDispose(arg); } }; int _tmain(void) { B * b = new D(); b->Dispose(); // as virtual as can be *g* }
The output is (as expected) D::Dispose() B::Dispose() D::InternalDispose(bool) B::InternalDispose(bool) Of course, in my final version I will mark B::Dispose() as __sealed and throw away D::Dispose() - AndreNothing new, just re-implementing IDisposable to create the impression of a virtual method (in which case you do not have to use the "Internal" attachment) - have fun. Best regards, Paul. Jesus Christ is LOVE! Please tell somebody.