Why can't I use interfaces like this?

G

Guest

I think it would be highly intuitive to use interfaces in the following manne

inteface IFo

void Invalidate()


class FooBa

System.Windows.Forms.Form winFrm
IFoo theFoo

...
theFoo = winFrm


Obviously, Forms do not implement the IFoo interface. However, they do implement all methods required by that interface, so why does the above code throw an invalid cast exception at runtime? At the very least I would think we could do explicit casts and let it go from there. To me, an IFoo object should mean any object with an .Invalidate method.

This would really save a lot of casting in my code if I could define my own interfaces then cast .NET types to these interfaces. For example, I have a component that is passed either a Sys.Win.Form or Sys.Win.Control. In the component itself, I only need to access the .Handle property and the .Invalidate method (both Form and Control types have both .Handle and .Invalidate()). Since I only need to be passed an object with a .Handle property and a .Invalidate method, my component could just store an IFoo interface type that requires a .Handle and a .Invalidate(). But alas, .NET won't let me do this, so I am forced to store 2 variables, a Form and a Control, then use only the one passed to my component

Can someone shed some light on why it is designed this way?
 
U

Uri Dor

interfaces represent "design by contract" and since Form's author never
heard of IFoo, I don't think it's fair to decide for him that Form
implements IFoo...
 
G

Guest

It's my code, why can't I decide that it is a type of IFoo? That's fair to me, after all, interfaces are the epitome of the "is-a" relationship; if a Sys.Win.Forms.Form "is-a" type of IFoo (if it implements IFoo's methods), even if the designer didn't specify it as IFoo, it should be accessible as an IFoo. Where am I wrong? I think this would be a very powerful feature as mentioned in the original post

----- Uri Dor wrote: ----

interfaces represent "design by contract" and since Form's author never
heard of IFoo, I don't think it's fair to decide for him that Form
implements IFoo..
 
K

Klaus H. Probst

That's not how interfaces work, on any language. C# performs a simple check
to ensure that your cast to IFoo is valid by making sure that the object
being cast implements it. The fact that it has methods with the same name is
irrelevant; if this sort of thing were permitted the language would be
useless. Interfaces are a *contract*, and contracts are enforced.

Why is it so difficult to just implement the interface in the Form
declaration? You can only inherit from one class but you can implement as
many interfaces as you want.


--
____________________
Klaus H. Probst, MVP
http://www.vbbox.com/


JudahH said:
I think it would be highly intuitive to use interfaces in the following manner

inteface IFoo
{
void Invalidate();
}

class FooBar
{
System.Windows.Forms.Form winFrm;
IFoo theFoo;

...
theFoo = winFrm;
}

Obviously, Forms do not implement the IFoo interface. However, they do
implement all methods required by that interface, so why does the above code
throw an invalid cast exception at runtime? At the very least I would think
we could do explicit casts and let it go from there. To me, an IFoo object
should mean any object with an .Invalidate method.
This would really save a lot of casting in my code if I could define my
own interfaces then cast .NET types to these interfaces. For example, I have
a component that is passed either a Sys.Win.Form or Sys.Win.Control. In the
component itself, I only need to access the .Handle property and the
..Invalidate method (both Form and Control types have both .Handle and
..Invalidate()). Since I only need to be passed an object with a .Handle
property and a .Invalidate method, my component could just store an IFoo
interface type that requires a .Handle and a .Invalidate(). But alas, .NET
won't let me do this, so I am forced to store 2 variables, a Form and a
Control, then use only the one passed to my component.
 
M

Mattias Sjögren

For example, I have a component that is passed either a Sys.Win.Form or Sys.Win.Control. In the component itself,
I only need to access the .Handle property and the .Invalidate method (both Form and Control types have both .Handle
and .Invalidate()). Since I only need to be passed an object with a .Handle property and a .Invalidate method, my
component could just store an IFoo interface type that requires a .Handle and a .Invalidate().

Form derives from Control, so just accept a Control reference and you
can still pass in a Form if you want.



Mattias
 
G

Guest

So it does (thanks for pointing that out). But my point still remains - what if I want to store any object with a particular method, ie if want to store either a Sys.IO.Stream or an instance of one of my classes, where both have a .Close method. In order for that to work, I'd have to store 2 variables and end up just using one, and throughout my code I'd continually have to check which one is null, and use the one that is not null. A real pain. Instead, I wish I could just specify I'll be storing a type with a .Close method.
 
M

Mattias Sjögren

But my point still remains - what if I want to store any object with a particular method, ie if want to store either
a Sys.IO.Stream or an instance of one of my classes, where both have a .Close method. In order for that to work, I'd
have to store 2 variables and end up just using one, and throughout my code I'd continually have to check which one
is null, and use the one that is not null. A real pain. Instead, I wish I could just specify I'll be storing a type
with a .Close method.

Have you considered using a delegate referring to the Close method
instead?

delegate void CloseDelegate();

CloseDelegate close;
if ( yourObj is Stream )
close = new CloseDelegate( ((Stream)yourObj).Close );
else if ( yourObj is YourOwnClass )
close = new CloseDelegate( ((YourOwnClass)yourObj).Close );

....

close();

A more generic way without the if statement would be

close = (CloseDelegate)Delegate.CreateDelegate( typeof(CloseDelegate),
yourObj, "Close" );



Mattias
 
S

Stu Smith

I think a more pragmatic reason is that it just doesn't happen often enough
to warrant that language feature.

I can imagine having an array of various controls, and wanting to invalidate
them all. I can't really imagine though a situation where you have a
heterogenous array of both controls and non-controls (which happen to have a
method called Invalidate), /and/ wanting to call Invalidate on them all.

In the situation you describe, won't IDisposable work?


JudahH. said:
So it does (thanks for pointing that out). But my point still remains -
what if I want to store any object with a particular method, ie if want to
store either a Sys.IO.Stream or an instance of one of my classes, where both
have a .Close method. In order for that to work, I'd have to store 2
variables and end up just using one, and throughout my code I'd continually
have to check which one is null, and use the one that is not null. A real
pain. Instead, I wish I could just specify I'll be storing a type with a
..Close method.
 

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

Top