How can I call base interface method?

  • Thread starter Thread starter jon
  • Start date Start date
J

jon

How can I call a base interface method?

class ThirdPartyClass :IDisposable { //I can not modify this class
void IDisposable.Dispose() {
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable {
void IDisposable.Dispose() {
Console.WriteLine( "MyClass Dispose" );
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}
 
How can I call a base interface method?

class ThirdPartyClass :IDisposable { //I can not modify this class
void IDisposable.Dispose() {
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable {
void IDisposable.Dispose() {
Console.WriteLine( "MyClass Dispose" );
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}

Good question - and to be honest, I don't *think* you can...
 
How can I call a base interface method?

class ThirdPartyClass :IDisposable { //I can not modify this class
void IDisposable.Dispose() {
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable {
void IDisposable.Dispose() {
Console.WriteLine( "MyClass Dispose" );
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}

Hi,

Usually when a base class implements an IDisposable, it also implements
a "protected virtual void Dispose(bool disposing)" where the acctually
cleanup is done... (if it is done correctly).
and the Dispose() method calls it.

try to override it as follow:

class ThirdPartyClass :IDisposable
{ //I can not modify this class
void IDisposable.Dispose()
{
GC.SuppressFinalize(this);
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable
{
protected override void Dispose(bool disposing)
{
// Do your cleanup here
Console.WriteLine( "MyClass Dispose" );
base.Dispose(disposing);
}
}

if it doesn't implement a Dispose(bool disposing)

then you should do as you did, only:

class ThirdPartyClass :IDisposable
{ //I can not modify this class
void IDisposable.Dispose()
{
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable
{
void IDisposable.Dispose()
{
Console.WriteLine( "MyClass Dispose" );
base.Dispose(); // just call the base class implementation of the
Dispose.
}
}

Cheers,
Eyal.
 
How can I call a base interface method?

class ThirdPartyClass :IDisposable { //I can not modify this class
void IDisposable.Dispose() {
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable {
void IDisposable.Dispose() {
Console.WriteLine( "MyClass Dispose" );
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}

Hi,

Usually when a base class implements an IDisposable, it also implements

a "protected virtual void Dispose(bool disposing)" where the acctually
cleanup is done... (if it is done correctly).
and the Dispose() method calls it.

try to override it as follow:

class ThirdPartyClass :IDisposable
{ //I can not modify this class
void IDisposable.Dispose()
{
GC.SuppressFinalize(this);
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
Console.WriteLine( "ThirdPartyClass Dispose" );
}

}

class MyClass :ThirdPartyClass, IDisposable
{
protected override void Dispose(bool disposing)
{
// Do your cleanup here
Console.WriteLine( "MyClass Dispose" );
base.Dispose(disposing);
}
}


if it doesn't implement a Dispose(bool disposing) and it implements the
IDisposable as: void IDisposable.Dispose(), then I guess you are
screwed... :(

Cheers,
Eyal.
 
My real problem involves a much more complicated class that uses
IBindingList.
I just used IDisposed in the posting as a simple example.

Like you say, I guess I am screwed.
 
Jon said:
My real problem involves a much more complicated class that uses
IBindingList.
I just used IDisposed in the posting as a simple example.

Like you say, I guess I am screwed.

HEY!!!! you are not screwed!!!!

I found you the answer!!!!

class MyClass :ThirdPartyClass, IDisposable
{
void IDisposable.Dispose()
{
// Do your cleanup here
Console.WriteLine( "MyClass Dispose" );

// Call the base.IDisposable.Dispose()
Type baseType = typeof(ThirdPartyClass);
InterfaceMapping map =
baseType.GetInterfaceMap(typeof(IDisposable));
map.TargetMethods[0].Invoke(this, new object[]{});
}
}


I just knew IDisposable has only one method, so I used
map.TargetMethods[0], you'll have to find your method in the
collection...

Good luck..

Eyal.
 
Eyal said:
HEY!!!! you are not screwed!!!!

I found you the answer!!!!

or even more generic:

class MyClass :ThirdPartyClass, IDisposable
{
void IDisposable.Dispose()
{
// Do your cleanup here
Console.WriteLine( "MyClass Dispose" );

// Call the base.IDisposable.Dispose()
InterfaceMapping map =
GetType().BaseType.GetInterfaceMap(typeof(IDisposable));
map.TargetMethods[0].Invoke(this, new object[]{});
}
}

Eyal.
 
Jon,

The problem here has to do with multiple inheritence. As you know, C# only
supports single inheritence. Of course, you can implement multiple
interfaces. But, what does this really mean?

If you think about it, it means you can only inherit one implementation.
From this persepective, the IDisposable interface cannot have
implementation. By definition, it is an interface, not an implementation.
Hence, in your derived class, you can have the Dispose() method. But, you
don't get to inherit any base class functionality.

Now to the Crux of it... But ThirdPartyClass is a class, so why can't I
inherit its functionality. And the reason is, because the Dispose method in
this class is explicitly defined as an interface only. If the base class had
been defined as:

class ThirdPartyClass : IDisposable
{ //I can not modify this class
public void Dispose()
{
Console.WriteLine("ThirdPartyClass Dispose");
}
}

or better yet:

class ThirdPartyClass : IDisposable
{ //I can not modify this class
public virtual void Dispose()
{
Console.WriteLine("ThirdPartyClass Dispose");
}
}

then you would be able to inherit from this member. In the former case you
could use the "new" keyword, and in the later case "override" to implement
your method. For example, in the former case:

public override void Dispose()
{
Console.WriteLine("MyClass Dispose");
base.Dispose(); // now this works
}

or in the later case:

public new void Dispose()
{
Console.WriteLine("MyClass Dispose");
base.Dispose(); // now this works
}

You can use some trickery to get at the base type and get its hidden
implementation. But the purpose of the explicit interface definition was to
hide it and not allow this.

The trickery involves using reflection to get to the actual implementation
of the base class, and force the hidden method invocation. For example, as
suggested by Eyal Safrin:

public virtual void Dispose()
{
Console.WriteLine("MyClass Dispose");
InterfaceMapping map =
base.GetType().BaseType.GetInterfaceMap(typeof(IDisposable));
map.TargetMethods[0].Invoke(this, new object[] {});
}

To fix this third party library once and for all, you might then create the
following wrapper class:

class ThirdPartyWrapper : ThirdPartyClass
{
public virtual void Dispose()
{
Console.WriteLine("Wrapper class");
InterfaceMapping map =
base.GetType().BaseType.GetInterfaceMap(typeof(IDisposable));
map.TargetMethods[0].Invoke(this, new object[] {});
}
}

class MyClass : ThirdPartyWrapper, IDisposable
{
public override void Dispose()
{
Console.WriteLine("MyClass Dispose");
base.Dispose();
}
}

Then use this class for all internal usage.

Hope this helps...
 
C# supports single inheritance of an implementation hierarchy and
multiple
inheritance of pure virtual classes aka interfaces in C#. Interfaces
provide the
same functionality as pure virtual classes in C++.

Regards,
Jeff
The problem here has to do with multiple inheritence. As you know, C#
only
supports single inheritence. Of course, you can implement multiple
interfaces. But, what does this really mean?
 
Since your implementation of IDisposable.Dispose() overwrite the original
entry of Dispose in the vtable there is no way to get back the pointer to
the original Dispose method.
If you find no other solution for your problem you can try with reflection.
 
How can I call a base interface method?

class ThirdPartyClass :IDisposable { //I can not modify this class
void IDisposable.Dispose() {
Console.WriteLine( "ThirdPartyClass Dispose" );
}
}

class MyClass :ThirdPartyClass, IDisposable {
void IDisposable.Dispose() {
Console.WriteLine( "MyClass Dispose" );
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}

Not easily, as you can't call an explicit interface implementation via
base.Dispose (which is the point of the question, I suppose).

Anyhow, try casting MyClass to its ancestral type, then casting the
ancestral type to IDispose, as below. Note, though, that
DisposableAncestor.Dispose() calls MyClass.IDisposable.Dispose - which
makes sense, given that you could cast DisposableAncestor back to
MyClass ....

class MyClass :ThirdPartyClass, IDisposable
{
private bool Disposed;

void IDisposable.Dispose()
{
if (Disposed) //DisposableAncestor.Dispose() calls this method
return;
else
Disposed = true;

Console.WriteLine( "MyClass Dispose" );

IDisposable DisposableAncestor = (IDisposable)
((ThirdPartyClass) this);
DisposableAncestor.Dispose();
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}
 
IDisposable DisposableAncestor = (IDisposable)
((ThirdPartyClass) this);
DisposableAncestor.Dispose();
//base.IDisposable.Dispose(); //How can I do this !!!!
}
}

This won't work due to the reasons a gave in my post.
 
Implementation of an interface is not inheritence. There is nothing to
inherit. You are simply required to implement the specific signature as
required by the interface.

But, the problem is not that you are overwriting the VTable as cody
mentioned. There is not VTable entry for this item. That is because in the
third party class, the item was not marked as virtual. Ultimatley, this is
the problem. If the Dispose method in the third party class is marked as
virtual, then the method may be overwritten, and the base functionality may
be called. Try it, it works.

Since you can't change the third party class, you have to use a hack to get
around it.
 
Cody,

The problem is that the method is not declared as virtual in the third party
class. Hence, the Dispose method is not virtual. (No VTable) Not the other
way around.

Frisky
 
AFAIK, interface methods asre called through a vtable.
If they wouldn't, how would the compiler determine the address of the method
if I say test.Dispose() where test is of type IDisposible? Test could be any
class.
Under the hood, interface methods are declared as sealed *and* virtual.
 
Cody,

Ok, you got me on a technicality. Internally, yeah, the compiler does some
wierd stuff to make things work.

And, I forgot to say that this was caused by the fact that the method is an
explicit interface method.

But, generically, the VTable is used to lookup virtual functions for a
class. Not an interface. (The "V" in VTable stands for virtual.)

Interfaces do not have virtual methods. Classes do. Interfaces do not have
implementations. Classes do.

In your example, you interchange interface and class; yet they are
distinctly different. (As shown above.)

Yes, when you implement a class, the interface methods in the class are
marked virtual, but final. Hence, you can "new" them, but not override them.
True virtual functions are those that may be overriden. The resaon the are
sealed (marked final) is because there is no inheritence. Unless of course
you implement them in a class, and then inherit from the class. But, then,
unless you mark the method virtual, you still can only new them.

However, in the example, the problem is that the method was declared as an
explicit interface. Internally this is seen as an override, but, it is an
override of an interface which has no implementation. Hence, you get no
inheritence. And, the compiler will not let you call the base method either,
because an interface does not have implementation.

As I pointed out in my other post, the method needs to be declared as a
regular class method to provide implementation inheritence. Since it is
defined explicitly as an interface (no implementation), the compiler won't
let you call the (as far as it is concerned) non-existent implementation.
Hence, you must resort to hack (reflection) to get at the implementation.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top