471,338 Members | 1,305 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,338 software developers and data experts.

Passing derived object of generic class to another class

Hey everyone --

Curious about some strange behaviour I'm seeing that seems to be
related to my lack of understanding on how generics work in C#. Here's
some simplified code (sorry for strange formatting) to show what my
issue is.

I have a generic abstract class here:

public abstract class MyGenericAbstractClass<Twhere T : MyInterface
{
//...whatever...
T _internal_interface;
public MyGenericAbstractClass(T internal_var)
{
_internal_interface = internal_var;
}
}

and I have classes that inherit from it, such as

public class MyDerived :
MyGenericAbstractClass<SomethingThatImplementsMyIn terface>
{
///...whatever...
public MyDerived(SomethingThatImplementsMyInterface internal_var) :
base(internal_var) { }
}

My problem comes when I try to pass my "MyDerived" objects to another
class, defined as such:

public class MyBrokenClass
{
// here I have a list of MyGenericAbstractClass objects
private
System.Collections.Generic.LinkedList<MyGenericAbs tractClass<MyInterface>>
_list_of_objects;

public void
AddMyGenericAbstractClassToPrivateLinkedList(MyGen ericAbstractClass<MyInterface>
object_to_add)
{
_list_of_objects.AddLast(object_to_add);
}
}

All of this compiles just fine.

When I try to do something like this though:
SomethingThatImplementsMyInterface my_something = new
SomethingThatImplementsMyInterface();

MyDerived my_derived = new MyDerived(my_something);
MyBrokenClass my_broken = new MyBrokenClass();
my_broken.AddMyGenericAbstractClassToPrivateLinked List(my_derived);

Then I get a compile time error as follows:
Error 1:
The best overloaded method match for
'MyBrokenClass.AddMyGenericAbstractClassToPrivateL inkedList(MyGenericAbstractClass<MyInterface>)'
has some invalid arguments

Error 2:
Argument '1': cannot convert from 'MyDerived' to
'MyGenericAbstractClass<MyInterface>'
So, what's the story? What have I done wrong?

Thanks kindly.
Mustafa


Jul 20 '08 #1
8 3019
On Sat, 19 Jul 2008 19:04:00 -0700, MMAS <mu***********@gmail.comwrote:
[...]
Error 2:
Argument '1': cannot convert from 'MyDerived' to
'MyGenericAbstractClass<MyInterface>'
So, what's the story? What have I done wrong?
The short answer: generics aren't covariant. That is, the type parameters
have to match exactly...just having the parameters related by inheritance
isn't sufficient.

Off the top of my head, I think that if you inherited
MyGenericAbstractClass<MyInterfaceinstead of
MyGenericAbstractClass<SomethingThatImplementsMyIn terfacefor MyDerived,
that would work. At least, that is, for the specific line you're having
trouble with (I can't say whether that would fit into the design you're
trying to do).

Other solutions involving changing the way you relate the types and
instances could work as well, but without knowing more about the bigger
picture, it's hard to say.

Pete
Jul 20 '08 #2
On Jul 19, 10:14*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Sat, 19 Jul 2008 19:04:00 -0700, MMAS <mustafasha...@gmail.comwrote:
[...]
Error 2:
* *Argument '1': cannot convert from 'MyDerived' to
'MyGenericAbstractClass<MyInterface>'
So, what's the story? What have I done wrong?

The short answer: generics aren't covariant. *That is, the type parameters *
have to match exactly...just having the parameters related by inheritance*
isn't sufficient.

Off the top of my head, I think that if you inherited *
MyGenericAbstractClass<MyInterfaceinstead of *
MyGenericAbstractClass<SomethingThatImplementsMyIn terfacefor MyDerived,*
that would work. *At least, that is, for the specific line you're having *
trouble with (I can't say whether that would fit into the design you're *
trying to do).

Other solutions involving changing the way you relate the types and *
instances could work as well, but without knowing more about the bigger *
picture, it's hard to say.

Pete
Jul 20 '08 #3
Ah, I see. Kinda a drag -- I suppose MyGenericAbstract doesn't have to
be a Generic and I can just cast it's private Interface variable to
the real type when deriving from it. It just doesn't seem as nice that
way...

Thanks for the information.

On Jul 19, 10:14*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Sat, 19 Jul 2008 19:04:00 -0700, MMAS <mustafasha...@gmail.comwrote:
[...]
Error 2:
* *Argument '1': cannot convert from 'MyDerived' to
'MyGenericAbstractClass<MyInterface>'
So, what's the story? What have I done wrong?

The short answer: generics aren't covariant. *That is, the type parameters *
have to match exactly...just having the parameters related by inheritance*
isn't sufficient.

Off the top of my head, I think that if you inherited *
MyGenericAbstractClass<MyInterfaceinstead of *
MyGenericAbstractClass<SomethingThatImplementsMyIn terfacefor MyDerived,*
that would work. *At least, that is, for the specific line you're having *
trouble with (I can't say whether that would fit into the design you're *
trying to do).

Other solutions involving changing the way you relate the types and *
instances could work as well, but without knowing more about the bigger *
picture, it's hard to say.

Pete
Jul 20 '08 #4
On Sun, 20 Jul 2008 11:00:11 -0700, MMAS <mu***********@gmail.comwrote:
Ah, I see. Kinda a drag -- I suppose MyGenericAbstract doesn't have to
be a Generic and I can just cast it's private Interface variable to
the real type when deriving from it. It just doesn't seem as nice that
way...
Well, unfortunately you haven't posted enough code for anyone else to
comment on what might be a better approach.

As one example: is there any real reason that your List<Thas to be a
List<MyGenericAbstractClass<MyInterface>>? One of the reasons covariance
isn't allowed in generics is that if it is, it opens the possibility for a
generic class being used in an unsafe way. The issue the compiler doesn't
like is that if you were allowed to convert from one form of the generic
type to another, the compiler can't maintain type safety any more. But
even if the compiler allowed that, you'd still have the type safety issue.

If you don't want to do the casting, then perhaps the alternative solution
is to fix your List<Tso that it uses
MyGenericAbstractClass<SomethingThatImplementsMyIn terfaceinstead of
MyGenericAbstractClass<MyInterface>. After all, if that's not always what
you're putting into the List<Tthen your code was broken anyway, and if
it is what you're putting into the List<T>, then changing the type should
be fine.

Of course, there's always the possibility that you're misusing generics
here anyway. The code you posted appears to have been abridged, so it's
not possible to comment on whether the rest of the generic class really
needs to be generic. But it doesn't seem to me that the part you showed
us does.

Pete
Jul 20 '08 #5
Hi again Peter -

I'm beginning to think that I do not need or even want generics in my
situation. My List<MyGenericAbstractClass<MyInterface>should really
become a List<MyGenericAbstractClassand MyGenericAbstractClass
should just have the _internal_interface typed as MyInterface.

I'm new to Generics and thought this was a situation I could use them
to get some code-time benefits. For example, I can get strongly typed
_internal_interface objects when I was coding my MyDerived objects.
The MyBrokenClass example, in the real code, is really a wrapper
around a collection of MyGenericAbstractClass objects that will be
calling a common method on all objects.

To get more detailed: my MyGenericAbstractClass in my real code is an
abstract "Step". The MyInterface class in my real code is the specific
arguments (StepArguments) for that step, and the MyBrokenClass is the
"StepManager" that calls the "RunStep" method for each Step object.
Using Generics seemed a good idea to ensure that each specific
implemented step got the correct type of Arguments and also so that I
can use those arguments while coding the Step without having to do any
casting. It seems that I was wrong.

I can gladly post more code if you'd like to see how I've really
implemented all of this, but figured a short explanation would be
easier than many lines of code.

Thanks again for the help.
Mustafa

On Jul 20, 1:20*pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
Well, unfortunately you haven't posted enough code for anyone else to *
comment on what might be a better approach.

As one example: is there any real reason that your List<Thas to be a *
List<MyGenericAbstractClass<MyInterface>>? *One of the reasons covariance *
isn't allowed in generics is that if it is, it opens the possibility for a *
generic class being used in an unsafe way. *The issue the compiler doesn't *
like is that if you were allowed to convert from one form of the generic *
type to another, the compiler can't maintain type safety any more. *But*
even if the compiler allowed that, you'd still have the type safety issue..

If you don't want to do the casting, then perhaps the alternative solution *
is to fix your List<Tso that it uses *
MyGenericAbstractClass<SomethingThatImplementsMyIn terfaceinstead of *
MyGenericAbstractClass<MyInterface>. *After all, if that's not always what *
you're putting into the List<Tthen your code was broken anyway, and if *
it is what you're putting into the List<T>, then changing the type should*
be fine.

Of course, there's always the possibility that you're misusing generics *
here anyway. *The code you posted appears to have been abridged, so it's *
not possible to comment on whether the rest of the generic class really *
needs to be generic. *But it doesn't seem to me that the part you showed *
us does.

Pete
Jul 20 '08 #6
On Sun, 20 Jul 2008 12:55:29 -0700, MMAS <mu***********@gmail.comwrote:
[...]
To get more detailed: my MyGenericAbstractClass in my real code is an
abstract "Step". The MyInterface class in my real code is the specific
arguments (StepArguments) for that step, and the MyBrokenClass is the
"StepManager" that calls the "RunStep" method for each Step object.
Using Generics seemed a good idea to ensure that each specific
implemented step got the correct type of Arguments and also so that I
can use those arguments while coding the Step without having to do any
casting. It seems that I was wrong.

I can gladly post more code if you'd like to see how I've really
implemented all of this, but figured a short explanation would be
easier than many lines of code.
I have to admit, it hasn't helped me much. Your phrase "to ensure that
each specific implemented step got the correct type of Arguments" doesn't
make sense to me. If each Step sub-class uses the same interface to
define their arguments, then isn't that the "type of Arguments"? And if
so, how can a sub-class get the wrong type of Arguments?

Conversely, if each Step sub-class uses some different combination of
arguments, then in what way does having some interface used by all the
sub-classes provide something useful? Wouldn't there be arguments that
could not be represented by the interface, because of the fact that
different sub-classes are using different combinations?

Based on what you've written so far, it does seem like you're mis-using
generics. But I'm afraid I'm unable to understand the intended design
well enough to offer better advice.

I agree that "many lines of code" probably wouldn't be helpful. But as
near as I can tell, we're only talking about four different types here:
your interface, your abstract class, one example of a sub-class, and your
manager class. Surely it should be possible to put together a more
complete code sample that what you posted earlier that illustrates why
it's useful to encapsulate your arguments as an interface, as well as why
simply doing that doesn't work for your manager class (i.e. what sort of
casting winds up happening that you thought would be solved by generics?).

I would think a useful sample of 50 lines or so, perhaps even less, would
suffice. If you'd like more consideration given of your design, maybe you
can try to come up with a simplified sample like that.

Pete
Jul 20 '08 #7
I've seen the folly of my ways, as they say. I've rid myself of the
Arguments class and moved the various arguments directly into each
derived Step class. I had a "validate" method on the Arguments
interface that I was calling before each step object was run by my
StepManager (to make sure all arguments were valid for this object),
but have now made this an abstract function in my abstract base "Step"
class that is implemented in each derived class.

Like many first attempts at using something "new", I think I was using
Generics just to use them rather than using them for the right
reasons.

I have to admit, it hasn't helped me much. *Your phrase "to ensure that*
each specific implemented step got the correct type of Arguments" doesn't*
make sense to me. *If each Step sub-class uses the same interface to *
define their arguments, then isn't that the "type of Arguments"? *And if *
so, how can a sub-class get the wrong type of Arguments?

Conversely, if each Step sub-class uses some different combination of *
arguments, then in what way does having some interface used by all the *
sub-classes provide something useful? *Wouldn't there be arguments that*
could not be represented by the interface, because of the fact that *
different sub-classes are using different combinations?

Based on what you've written so far, it does seem like you're mis-using *
generics. *But I'm afraid I'm unable to understand the intended design *
well enough to offer better advice.

I agree that "many lines of code" probably wouldn't be helpful. *But as*
near as I can tell, we're only talking about four different types here: *
your interface, your abstract class, one example of a sub-class, and your*
manager class. *Surely it should be possible to put together a more *
complete code sample that what you posted earlier that illustrates why *
it's useful to encapsulate your arguments as an interface, as well as why*
simply doing that doesn't work for your manager class (i.e. what sort of *
casting winds up happening that you thought would be solved by generics?)..

I would think a useful sample of 50 lines or so, perhaps even less, would*
suffice. *If you'd like more consideration given of your design, maybe you *
can try to come up with a simplified sample like that.

Pete
Jul 21 '08 #8
On Sun, 20 Jul 2008 17:08:51 -0700, MMAS <mu***********@gmail.comwrote:
[...]
Like many first attempts at using something "new", I think I was using
Generics just to use them rather than using them for the right
reasons.
That does happen sometimes. :)

But now, if and when you are using generics for something that could
actually benefit from them, and you run into the lack of covariance again,
at least you'll have seen the issue before and understand it. So your
effort wasn't entirely wasted. :)

Anyway, glad you got your code straightened out.

Pete
Jul 21 '08 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

24 posts views Thread by Brad Marts | last post: by
6 posts views Thread by Gernot Frisch | last post: by
7 posts views Thread by Ken Allen | last post: by
1 post views Thread by Mark McDonald | last post: by
4 posts views Thread by Charles Churchill | last post: by
11 posts views Thread by Frederic Rentsch | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.