One Object, two possible types

J

James CC

Hi there,

I have a function, converted from VB, that is passed an object, and sets it
up. The object passed is either a ListBox or a ComboBox. The code checks to
make sure that the object passed is one of the two types, and then does some
work. I provide a cut-down version (the first code).

The problem is that, with the exception of one line (setting the ComboBox
DropDownStyle) the work done on the items is exactly the same, but I don't
know how to simplify the code by making a variable that is EITHER a ComboBox
OR a ListBox, but unspecified, with the relevant Methods and Properties
available of both. A (non-working) example is the second code.

In the code, Box.DoStuff() is things like .BeginUpdate(), .Items.Clear(),
and so on.

Is there any way to do this? Do I have to have separate code for each type
(ComboBox and ListBox), or perhaps separate functions? I suppose I could
possibly do some funky inheritance thing, creating special classes, but this
is only two functions, so it seems like overkill.

Thanks in advance, and apologies for any Newbieness

James

public void SetBoxUp(object TheListControl)
{
if ( ! ( TheListControl.GetType() == typeof(ListBox) ||
TheListControl.GetType() == typeof(ComboBox) ) )
return;

ListControl lc = (ListControl) TheListControl;
lc.DoStuff(); // do things that are accessable to a ListControl

if ( TheListControl.GetType() == typeof(ComboBox) )
{
ComboBox cb = (ComboBox) TheListControl;
cb.DropDownStyle = ComboBoxStyle.DropDownList;
cb.DoStuff(); // do things that are accessable to a ComboBox
}
else
{
ListBox lb = (ListBox) TheListControl;
lb.DoStuff(); // do things that are accessable to a ListBox
}
}



public void SetBoxUpNew(object TheListControl)
{
if ( ! ( TheListControl.GetType() == typeof(ListBox) ||
TheListControl.GetType() == typeof(ComboBox) ) )
return;

((ListControl) TheListControl).DoStuff(); // do things that are
accessable to a ListControl

if ( TheListControl.GetType() == typeof(ComboBox) )
((ComboBox) TheListControl).DropDownStyle =
ComboBoxStyle.DropDownList;

// Get the object type, and use to Class the object correctly, then
DoStuff() - this doesn't work
( (TheListControl.GetType()) TheListControl).DoStuff(); // do
things that are accessable to a ComboBox and ListBox
}
 
N

Nassos

Hi James,
You could mask the object as Control first and setup the common properties
and then mask as each control for the speciffic properties.
hope that helps
 
C

Carlos J. Quintero [.NET MVP]

Both ListBox and ComboBox inherit from ListControl, so you can cast to that
class and use its methods.

--

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio .NET, VB6, VB5 and VBA
You can code, design and document much faster.
Free resources for add-in developers:
http://www.mztools.com
 
J

JamesCC

Hi Nassos,

Thanks for your reply.

I'm not totally sure what you mean by 'masking'. I tried casting the object
to ListBox to access the methods and properties common to both, but when the
object passed was a CheckBox I got an error.

How does one mask?

James
 
J

JamesCC

Dear Carlos,

Thanks for taking the time to answer.

I am trying to access Methods and Parameters that are present in ListBox and
ComboBox, but not ListControl, for example .BeginUpdate(), .EndUpdate(),
..Items[], and so on. As far as I know you can't access those through a
ListControl, can you?

James
 
L

larrylard

I had been about to post what Carlos did, but then I checked the docs
and found what you did - that there are members which are present in
both ComboBox and ListBox - with identical semantics - but which are
NOT defined in their parent class ListControl. This is arguably an
oversight on the part of the Framework creators, although there might
be a good reason why they did it this way.

As it is, I don't think there's any way around the inelegance of
(pseudo-code)

If it's a combobox
((combobox)it).beginupdate
((combobox)it).items.clear
...
Else
((listbox)it).beginupdate
((listbox)it).items.clear
...

If we were in an environment where late-binding were possible (eg
VBScript, non-Strict VB), *then* we could just say

var.beginupdate
var.items.clear
....

BUT to my mind the performance loss from late binding, and the safety
loss from weak typing are too high a price for the code clarity gains.

Enter the long-winded code and mutter curses at the Framework, is the
best we can do here.


Dear Carlos,

Thanks for taking the time to answer.

I am trying to access Methods and Parameters that are present in ListBox and
ComboBox, but not ListControl, for example .BeginUpdate(), .EndUpdate(),
.Items[], and so on. As far as I know you can't access those through a
ListControl, can you?

James

Carlos J. Quintero said:
Both ListBox and ComboBox inherit from ListControl, so you can cast to
that class and use its methods.

--

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio .NET, VB6, VB5 and VBA
You can code, design and document much faster.
Free resources for add-in developers:
http://www.mztools.com
 
J

JamesCC

Dear Larry,

Thank you for your considered and clear answer (not implying anything
against the others, though). Yeah, I'd suspected that might be the case; I'm
not totally comfortable with objects in C#, coming from a C background, and
I hoped there was something I didn't know, some sort of way of creating a
variable that was a class of both ListBox and ComboBox.

I have considered creating a class that inherits from ComboBox and ListBox
(I seem to recall that's possible) and then passing and using that, but I'm
not at home, so I haven't tried it yet. It may not work.

For one moment I really thought some variation on the following might work.
( (TheListControl.GetType()) TheListControl).DoStuff();
It didn't. I also looked for a specific Function or Method that would cast
something, for similar use, eg:
((TheListControl.GetType().SetClass(TheListControl)).DoStuff();
Didn't find it yet.

Your comments on VB (which I don't use) are interesting, and pertinent,
since the original source code was in VB, and indeed did not differentiate
between the two classes. It is a simple way of creating a ComboBox or
ListBox containing word and color rectangle examples of either all
'KnownColors' or 'SystemColors' or Web Colors. Two short functions. If
anyone wants, I could post the original VB and my C# versions, for interest.

I guess at the end of the day, the difference this makes to my code is
minimal, but I was more interested for the sake of understanding classes and
objects a little better. I thought this might be the sort of thing that OOP
languages did easily.

Thanks for taking the time,

James


I had been about to post what Carlos did, but then I checked the docs
and found what you did - that there are members which are present in
both ComboBox and ListBox - with identical semantics - but which are
NOT defined in their parent class ListControl. This is arguably an
oversight on the part of the Framework creators, although there might
be a good reason why they did it this way.

As it is, I don't think there's any way around the inelegance of
(pseudo-code)

If it's a combobox
((combobox)it).beginupdate
((combobox)it).items.clear
...
Else
((listbox)it).beginupdate
((listbox)it).items.clear
...

If we were in an environment where late-binding were possible (eg
VBScript, non-Strict VB), *then* we could just say

var.beginupdate
var.items.clear
....

BUT to my mind the performance loss from late binding, and the safety
loss from weak typing are too high a price for the code clarity gains.

Enter the long-winded code and mutter curses at the Framework, is the
best we can do here.
 
C

Carlos J. Quintero [.NET MVP]

Yes, if the methods are duplicated in ListBox and ComboBox rather than
implemented in the ListControl base, you have to cast to the proper class.
This is the best approach.

There is other approach but it is overkill: you can call methods and
properties by name of any object using Reflection (VB.NET allows to do this
with Option Strict Off too):

// Not tested
Type myType;
myType = myObject.GetType();
myType.InvokeMember("BeginUpdate",...., myObject,...)

--

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio .NET, VB6, VB5 and VBA
You can code, design and document much faster.
Free resources for add-in developers:
http://www.mztools.com

<[email protected]> escribió en el mensaje

I had been about to post what Carlos did, but then I checked the docs
and found what you did - that there are members which are present in
both ComboBox and ListBox - with identical semantics - but which are
NOT defined in their parent class ListControl. This is arguably an
oversight on the part of the Framework creators, although there might
be a good reason why they did it this way.

As it is, I don't think there's any way around the inelegance of
(pseudo-code)

If it's a combobox
((combobox)it).beginupdate
((combobox)it).items.clear
...
Else
((listbox)it).beginupdate
((listbox)it).items.clear
...

If we were in an environment where late-binding were possible (eg
VBScript, non-Strict VB), *then* we could just say

var.beginupdate
var.items.clear
....

BUT to my mind the performance loss from late binding, and the safety
loss from weak typing are too high a price for the code clarity gains.

Enter the long-winded code and mutter curses at the Framework, is the
best we can do here.
 
S

Samuel R. Neff

We ran into a similar situation using COM objects from ArcIMS. At one
point they provide a collection of "Layers" which can be one of four
different types of layers. However, there was no Layer base class or
interface or anything so there was no way to access the common methods
polymorphically.

What we ended up doing was creating our own wrapper classes which did
have an inheritance structure. So given this:

ALayer
BLayer
CLayer

each has an ID property,

we created

abstract LayerWrapper {
abstract property ID;
}

ALayerWrapper {...}
BLayerWrapper {...}
CLayerWrapper {...}

And a Wrap static function which does type inspection and returns the
appropriate wrapper. That way the type inspection is in one place and
all calls can go through the base wrapper.

Now we had a lot more calls so maybe the extra work isn't worthwhile
in your case (development work--runtime impact is negligible), but
this is one option.

HTH,

Sam
 

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