Generic Properties/Methods

A

Andrew Ducker

I have a collection of classes descending from a single root class
(let's call it RootClass). They all currently have a property of
Logical, of type Logical. However they actually return a subclass of
Logical (LogicalA, LogicalB). I'm currently casting them to the right
type when I retrieve them, but obviously this isn't terribly 'nice'.

I tried converting the class to be generic, and having a type parameter
that affected the type of the Logical property. But then I couldn't
have a single pointer variable that could point to any instance of the
class, as you can't cast from one generic class to another - i.e. you
can't have
RootClass<object> = RootClass<TextBox>;
and some of my code depends on keeping a point to the currently active
class.

So, I thought, I'll try creating a separate method
GetLogical<LogicalType> and then converting it from an open to a closed
type in the sublclass.

But it seems you can't close an open generic method as:
class BaseReturner
{
public virtual T GetLogical<T>() where T : new()
{
return default(T);
}

class TextBoxReturner : BaseReturner
{
public override TextBox GetLogical<Windows.Forms.TextBox>()
{
return new TextBox();
}
}

returns an error.

Is there any way of doing this, or should I just go back to casting
things back and forth?

Cheers,

Andy
 
J

Joanna Carter [TeamB]

"Andrew Ducker" <[email protected]> a écrit dans le message de (e-mail address removed)...

|I have a collection of classes descending from a single root class
| (let's call it RootClass). They all currently have a property of
| Logical, of type Logical. However they actually return a subclass of
| Logical (LogicalA, LogicalB). I'm currently casting them to the right
| type when I retrieve them, but obviously this isn't terribly 'nice'.
|
| I tried converting the class to be generic, and having a type parameter
| that affected the type of the Logical property. But then I couldn't
| have a single pointer variable that could point to any instance of the
| class, as you can't cast from one generic class to another - i.e. you
| can't have
| RootClass<object> = RootClass<TextBox>;
| and some of my code depends on keeping a point to the currently active
| class.

One solution is to have a non-generic base class to the generic one and put
non-type-specific properties/methods in that.

class RootClass
{
...
}

class RootClass<typeT> : RootClass
{
...
}

| So, I thought, I'll try creating a separate method
| GetLogical<LogicalType> and then converting it from an open to a closed
| type in the sublclass.
|
| But it seems you can't close an open generic method as:
| class BaseReturner
| {
| public virtual T GetLogical<T>() where T : new()
| {
| return default(T);
| }
|
| class TextBoxReturner : BaseReturner
| {
| public override TextBox GetLogical<Windows.Forms.TextBox>()
| {
| return new TextBox();
| }
| }

Try a generic static version of BaseReturner, and then you can have a
generic method that returns the appropriate object.

public static class Returner<typeT> where typeT : new()
{
public static typeT GetLogical()
{
return new typeT();
}
}

Then you can simply call :

{
TextBox tb = Returner<TextBox>.GetLogical();
...
}

But then you might just as well have a non-virtual generic method in a
generic base class. Then the type will always be correct.

public class RootClass<typeT> where typeT : new()
{
public typeT GetLogical()
{
return new typeT();
}

...
}

public class TextBoxRootClass : RootClass<TextBox> { }


{
RootClass test = new TextBoxRootClass();

TextBox box = test.GetLogical();

...
}

Joanna
 
A

Andrew Ducker

Joanna said:
But then you might just as well have a non-virtual generic method in a
generic base class. Then the type will always be correct.

But the problem is that I want to make sure that there is always a
method/property that returns a Logical, but I want the exact subtype of
Logical to be changable with the subclass that's returning it.

Let's say I'm working with different kinds of jobs (Gardener, Chef,
etc.) I have a bunch of JobPanels, each of which returns a JobInfo.

I _want_ to create a JobPanel<JobInfoType> : where JobInfoType :
JobInfo.

Then I could create a class of ChefInfo : JobInfo and a ChefPanel :
JobPanel<ChefInfo>.

And in fact I _can_ do that. But I also want to know what the current
open JobPanel is. And I can't have
JobPanel currentJobPanel = ...
because there is no base class.

I suppose I could create a JobPanel, and then create a
JobPanel<JobInfoType> subclassing from it, that merely added the
returning JobInfo. That would make sense.

Seems kinda hackish though.

Andy
 
J

Joanna Carter [TeamB]

"Andrew Ducker" <[email protected]> a écrit dans le message de (e-mail address removed)...

| But the problem is that I want to make sure that there is always a
| method/property that returns a Logical, but I want the exact subtype of
| Logical to be changable with the subclass that's returning it.

Ok, if you want to guarantee that the type returned is always derived from a
base class, then state that in the constraints :

public abstract class RootClass<typeT> where typeT : Logical, new()
{
public abstract typeT GetLogical();

...
}

public class TextBoxRootClass : RootClass<TextBoxLogical>
{
public override typeT GetLogical()
{
return new TextBoxLogical();
}
}


{
RootClass test = new TextBoxRootClass();

// either

Logical logical = test.GetLogical()

// or

TextBoxLogical textBoxLogical = test.GetLogical();

...
}

| Let's say I'm working with different kinds of jobs (Gardener, Chef,
| etc.) I have a bunch of JobPanels, each of which returns a JobInfo.
|
| I _want_ to create a JobPanel<JobInfoType> : where JobInfoType :
| JobInfo.
|
| Then I could create a class of ChefInfo : JobInfo and a ChefPanel :
| JobPanel<ChefInfo>.
|
| And in fact I _can_ do that. But I also want to know what the current
| open JobPanel is. And I can't have
| JobPanel currentJobPanel = ...
| because there is no base class.
|
| I suppose I could create a JobPanel, and then create a
| JobPanel<JobInfoType> subclassing from it, that merely added the
| returning JobInfo. That would make sense.

In theory, there is no need for a common base class like System.Object; all
classes could be compiled to automatically include that functionality; but
separating out such a base class allows us to put any kind of object into a
System.Object reference, even though we might not really want the
functionality that that object requires.

Using generic classes can also require a non-generic base class for the
reasons that you have found. I don't think this is particularly "hackish",
simply a separation of concerns between those parts of a class hierarchy
that need to be generic from those that don't.

C# doesn't allow co-variance of generic types because of all the problems
that this could cause; once a MyThing<int> is cast to a MyThing<object> I am
now allowed to assign anything that derives from System.Object to
parameterised properties of that class, even though they are not ints...
Ouch !!

Does that help or hinder :)

Joanna
 
A

Andrew Ducker

Joanna said:
C# doesn't allow co-variance of generic types because of all the problems
that this could cause; once a MyThing<int> is cast to a MyThing<object> I am
now allowed to assign anything that derives from System.Object to
parameterised properties of that class, even though they are not ints...

Yeah - I reached that conclusion - GetInt would convert to GetObject
just fine, but SetInt isn't going to like being sent objects at all.
Which means it _could_ work for things that were read only, but that
sounds like a lot of work for not much reward on the part of the
language designers.

Being able to "close" an "open" generic method would still be nice, but
I can live without it.

Thanks for your help.

Andy
 

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