|
I have two classes A and B , both of which have MyMethod() .
Now this is my problem:
A a = new B();
But the compiler complains that it is not possible even though they both have MyMethod() method.
Do you know why it is designed this way?
Don't forget, that's Persian Gulf not Arabian gulf!
Murphy: Click Here![^] I'm thirsty like sun, more landless than wind...
|
|
|
|
|
You're not making sense. Of course you can't do that conversion; classes A and B are not compatible even if they share a method (or even all methods).
However, an interface is supposed to work like that; ICloneable specifies a .Clone method, and all objects that implement ICloneable have a .Clone method. If I create my own interface IFoo that specifies a .Clone method, any class that is ICloneable should be convertible to IFoo.
Here's an example situation I ran into last night that brought about this question. I have a component that is passed either a Sys.Win.Forms.Form object or a Sys.Win.Forms.Control object. It is completely up to the consumer of my component whether to pass a Form or a Control . In my component class, the only thing I care about is that the passed object, either Form or Control, have a .Handle getter property and a .Invalidate() method. Because both Form and Control have these types, it would be ideal if I could create my own interface and store that type, like so:
interface IHandleWithInvalidate
{
IntPtr Handle{get;}
void Invalidate();
}
class myComponent
{
private IHandleWithInvalidate passedObject;
public myComponent(Form f)
{
this.passedObject = f;
}
public myComponent(Control c)
{
this.passedObject = c;
}
private void DoSomething()
{
this.passedObject.Invalidate();
IntPtr h = this.passedObject.Handle;
}
}
Alas, .NET won't let me do this. Instead, I have to keep 2 variables, and throughout my code, I have to check which one to use, nearly doubling the amount of code I have to write. For example, the above snippet would now look like this:
class myComponent
{
private Form passedForm;
private Control passedControl;
public myComponent(Form f)
{
this.passedForm = f;
}
public myComponent(Control c)
{
this.passedControl = c;
}
private void DoSomething()
{
if(this.passedForm != null)
{
this.passedForm.Invalidate();
IntPtr h = this.passedForm.Handle;
}
else
{
this.passedControl.Invalidate();
IntPtr h = this.passedControl.Handle;
}
}
}
As you can see in the DoSomething() method, I have to write 10 lines of code instead of 2. Given that I'll be using my passed object often, one can clearly see the side effects of using such a model.
I think C# should have some construct to allow me to accomplish a similar task without writing extra lines of code; if not interfaces, then maybe something like C unions. What do you guys think?
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
Because in .net (and java and lots of other languages) interfaces have to be declared in class declration. Since Form does not implement IFoo can't convert it to IFoo. What you're looking for is named interface semantics and .net has structural interface semantics.
|
|
|
|
|
The form (which you must derive from System.Windows.Form ) must implement the interface. This is by design and is common in many languages (including all .NET languages - if they support interfaces, Java and C++).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks for the reply. Yeah I realize that it must implement the interface to actually work. So maybe an interface is not the right solution, maybe a new C# construct would be a better solution. For instance, if I were to have a component class that was passed either a DataView or a BinaryWriter object, and the component itself only cared about the .Close method of either the DataView or the BinaryWriter, I could write the following code:
public SpecialC#Construct
{
has a .Close method
}
public class myComponent
{
private SpecialC#Construct passedObject;
public myComponent(DataView v)
{
this.passedObject = v;
}
public myComponent(BinaryWriter b)
{
this.passedObject = b;
}
public void DoSomething()
{
this.passedObject.Close();
}
}
This is really what I'm trying to do. But since I'm not allowed to do that with interfaces, and there's no other construct that'll let me do that, I'm forced to write the above like so:
public class myComponent
{
private DataView passedDataView;
private BinaryWriter passedWriter;
public myComponent(DataView v)
{
this.passedDataView = v;
}
public myComponent(BinaryWriter b)
{
this.passedWriter = b;
}
public void DoSomething()
{
if(passedDataView != null)
{
passedDataView.Close();
}
else
{
passedBinaryWriter.Close();
}
}
}
Given that I'd be using the passed object very often in my code, be it a DataView or a BinaryWriter, that will roughly double the number of lines I have to write, as seen in the DoSomething method. From what I can tell, there doesn't seem to be a good way to do this.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
You are trying to circumvent the strongly typed system in .Net. You should write a shim object that behaves like a DataView or a BinaryWriter through that shim object/interface. This shim will have Close and any other logic to call the right things.
Too many times people try to use "code reuse" to get out of the wrong type of work. You have a situation where you have two objects that behave in a similiar manner but aren't related. The logic to determine which one is applicable has to exist somewhere.
ps. Even in C++, the results of doing what you were doing is somewhat unexpected (and often frowned upon). Close could be any method on any object in the inheritance chain. If the v-table is built arbitrarialy (ie. in a random order) then who knows which object version of Close you just called. It is one the banes of having a system where multiple inheritance exists.
|
|
|
|
|
Tom Larsen wrote:
You are trying to circumvent the strongly typed system in .Net. You should write a shim object that behaves like a DataView or a BinaryWriter through that shim object/interface. This shim will have Close and any other logic to call the right things.
Yeah I figured that's what would be suggested. I hate to write an extra object just for this simple problem, but I suppose it would be better than writing it out as previously posted.
Thanks for the replies Tom and Heath.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
Why do you care about a Close method? If you want to make sure something's closed, then you're going about it the wrong way. Instead, accept an IDisposable and call Dispose on the object. It doesn't matter what the implementation is, then. IDisposable is implemented by objects that have to clean up resources, like streams and the like. It will close any handles that are open for you. THAT's what you need to worry about if I follow your train of thought correctly. See the documentation for the IDisposable interface in the .NET Framework SDK for more information.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Simply put: System.Windows.Forms.Form does not implement IFoo . I'm not sure why you thought Form did. Is it because of Invalidate (which Form gets from Control no less)? Again, Control.Invalidate() has nothing to do with IFoo.Invalidate() at all. There is no possible cast. Period.
|
|
|
|
|
Tom Larsen wrote:
Simply put: System.Windows.Forms.Form does not implement IFoo. I'm not sure why you thought Form did.
Right, I understand it doesn't explicitly implement IFoo. In a way though, because it implements all methods of IFoo, it *kind of* implements it, in that it implements all the methods of IFoo without actually implementing it explicitly.
And again to stress, I know I can't cast a Form to IFoo. The original post was simply a question of ~why~ .NET won't let me do it, and to see if there were any better ways of conquering the said problem.
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
Judah H. wrote:
n a way though, because it implements all methods of IFoo, it *kind of* implements it, in that it implements all the methods of IFoo without actually implementing it explicitly.
Nope, just because you write an interface that defines methods that another class has does not make a binding contract between the existing class and your interface. Classes must be aware of the interfaces they implement at compile time, this is why you will get compiler errors if you write some class and tell it to implement some interface and you do not providing a said implementation. You can't write a class that implements some method and then at runtime tell it that that implementation belongs to an interface that it wasn't assigned to the class at compile time.
- Nick Parker My Blog
|
|
|
|
|
Hi.
<br />
bool FrmIsOpen = false; <br />
<br />
for (int i=0; i < this.MdiParent.MdiChildren.Length; i++) <br />
{ <br />
if (this.MdiParent.MdiChildren[i].GetType() == typeof(FrmPassword)) <br />
{ <br />
FrmIsOpen = true; <br />
break; <br />
} <br />
}<br />
<br />
if (!FrmIsOpen) <br />
{ <br />
FrmPassword r = new FrmPassword(); <br />
r.MdiParent = this;<br />
r.Show(); <br />
} <br />
An unhandled exception of type 'System.NullReferenceException' occurred in CLINICINFORMATIONSYSTEM.exe
Additional information: Object reference not set to an instance of an object.
the error's pointing to the line that has been bold...i dont understand what is it trying to say?....
CODER
|
|
|
|
|
It's trying to tell you that something is null; this.MdiParent or MdiParent.MdiChildren is null. Check for that condition before entering the loop.
---------------------------
He who knows that enough is enough will always
have enough.
-Lao Tsu
|
|
|
|
|
Hi,
Im sorry Judah, im a beginner...i would appreciate it if you could show me how i can do that.
thx in advance
CODER
|
|
|
|
|
bool FrmIsOpen = false;
if(this.MdiParent != null && this.MdiParent.MdiChildren != null)
{
for (int i=0; i < this.MdiParent.MdiChildren.Length; i++)
{
if (this.MdiParent.MdiChildren[i].GetType() == typeof(FrmPassword))
{
FrmIsOpen = true;
break;
}
}
}
if (!FrmIsOpen)
{
FrmPassword r = new FrmPassword();
r.MdiParent = this;
r.Show();
}
---------------------------
He who knows that enough is enough will always
have enough.
-Lao Tsu
|
|
|
|
|
My first question would be where is this code sitting?
Is it in a child form or an MDIParent? It looks like a parent form has this code, in which case the parent form has no MDIParent. This reference would be null, and therefor, your reference to 'this.MdiParent.MdiChildren.Length' would return null. If this code is in a parent form, then your reference should be this.MdiChildren.Length.
RageInTheMachine9532
|
|
|
|
|
its in a parent form. i tried editing the code your way..but it is still able to open up two same forms...
<br />
bool FrmIsOpen = false; <br />
<br />
if(this.MdiParent != null && this.MdiChildren != null)<br />
{<br />
for (int i=0; i < this.MdiChildren.Length; i++) <br />
{ <br />
if (this.MdiParent.MdiChildren[i].GetType() == typeof(FrmPassword)) <br />
{ <br />
FrmIsOpen = true; <br />
break; <br />
} <br />
}<br />
}<br />
if (!FrmIsOpen) <br />
{ <br />
FrmPassword r = new FrmPassword(); <br />
r.MdiParent = this;<br />
r.Show(); <br />
} <br />
CODER
|
|
|
|
|
OK. The loop now runs but your references in your if statement are still screwed up. Use this instead:
bool FrmIsOpen = false;
if (this.MdiChildren.Length > 0)
for (int i=0; i < this.MdiChildren.Length; i++)
{
if (this.MdiChildren[i].GetType() == GetType(FrmPassword))
{
FrmIsOpen = true;
break;
}
}
}
if (!FrmIsOpen)
{
FrmPassword r = new FrmPassword();
r.MdiParent = this;
r.Show();
}
The first bolded statement was changed because 'this.MDIParent' will always return null if 'this' is an MDIParent. This was changed to checking if the MDIChildren collection has anything in it. In the second bolded statement, the 'typeof()' reference was changed to 'GetType()'. If you have to, you could change this to 'Type.GetType()'. This should take care of your problem.
RageInTheMachine9532
|
|
|
|
|
hey guys,
well this is my problem. I am trying to read a text file ,with information such as these three lines, insert it into the program, then seperate them into a usable format for use. There are about 1000 such lines, but speed is not neccessarily an issue. Thanks for the help.
501,Red_Potion,Red Potion,0,50,,70,,,,,10477567,2,,,,,
502,Orange_Potion,Orange Potion,0,200,,100,,,,,10477567,2,,,,,
503,Yellow_Potion,Yellow Potion,0,550,,130,,,,,10477567,2,,,,,
i was kinda wondering if there was same way to use a multidimentional array where the rows are the text files lines and the columns are the different values.
|
|
|
|
|
how about:
ArrayList table = new ArrayList;
SreamReader txtFile = new StreamReader("myfile.txt");
while ((string reader = txtFile.ReadLine()) != null) {
table.add(reader.Split(","));
}
txtFile.Close();
Matthew Hazlett
Windows 2000/2003 MCSE
Never got an MCSD, go figure...
|
|
|
|
|
Hi!
does anyone have some experience with Jpeg2000 and .NET ???
can someone give me some code samples how to compress a picture to
Jpeg2000 with .NET ???
and how to show a Jpeg2000 picture although the picture is not loaded
complete??? (show the Jpeg2000 picture with a lower quality).
how to send (upload) DICOM Header of a Jpeg2000 picture???
best regards,
gicio
|
|
|
|
|
Hi!
does anyone have some experience with BITS
(Background Intelligent Transfer Service) and .NET ???
can someone give me some code samples how to use BITS with .NET ???
regards,
gicio
|
|
|
|
|
Check MSDN, there are several example articles there.
- Nick Parker My Blog
|
|
|
|
|
|
Hi!!
does anyone some experience with BITS
(Background Intelligent Transfer Service) and SSL and .NET ????
can someone give me some code samples how to use it?
regards,
gicio
|
|
|
|
|