The situation is that we have a tree of "Node" objects. A Node is a
visualizable item, like a component. THe menues of all or ouf applications,
for example, are node hierarchies that an adapter transposes into a menu
model.
Now, Nodes have an internal DataObject, which can hold the actual data -
often a business object. This was so far a Object, now it will be T.
So, the definition of Node looks like this now:
public class Node<T> :
SmartObject,
INamed
where
T : class
{
The T is supposed to indicate the type of the DataObject, which can be any
class. There is a class NodeList that is basically a glorified IList with a
lot of additional functionality. It looks like this:
public class NodeList<T> :
ObjectBindingList<T>
where
T : Node<Object>
{
The idea is that a NodeList can hold any Node and should be strong-typable
for this. Now, here the issues come. A Node itself has a Collection
"Children". This is similar to the collection if children in the component
hierarchy. Nodes are not restricted to subtypes - and the constructor of the
NodeList can take a Node that is the parent. If there is a parent in a
NodeList, there is a lot of stuff going on when you add/remove thigs. So,
there is aconstructor like this:
public NodeList(Node<Object> Parent)
As you can see, ANY Node can be the parent.
And here the issues start. In the constructor of the Node I create the
ChildNodes:
_ChildNodes = new NodeList<Node<Object>> (this);
And the issue is: this blows. And I have no clue why. The error messages
are:
Error 2 The best overloaded method match for
'Foundation.Nodes.NodeList<Foundation.Nodes.Node<object>>.NodeList(Foundation.Nodes.Node<object>)'
has some invalid arguments
C:\WORK\ThonaConsulting\EntityBroker\03.0\Foundation\Nodes\Node.cs 29 18
Foundation
Error 3 Argument '1': cannot convert from 'Foundation.Nodes.Node<T>' to
'Foundation.Nodes.Node<object>'
C:\WORK\ThonaConsulting\EntityBroker\03.0\Foundation\Nodes\Node.cs 29 46
Foundation
Now, this I simply do not understand. The argument "this" is a Node<T> - and
is not convertible to Node<object>? Why not? T is supposed to be a class,
and object is the base-class of all classes. Also, I cano not even cast
this:
_ChildNodes = new NodeList<Node<Object>> ((Node<T>)this);
produces the exactly SAME error. I simply do not understand why. As I said,
the case should be totally valid in my optinion.
Anyone a clue? This starts to look like a compiler error to me, but I still
fear I just overlook something. I mean, this is created WITHIN A node, so
thi sshould be totally valid, or?
Thomas Tomiczek
The reason for this is that with generics, if you have a class B, that
inherits from A, then C<B> does NOT inherit from C<A>. The same goes for
casting.
To get around this, you should have a non-generic interface which
exposes the functionality of your node, and pass that around to the
constructor of your node class.
Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- m...@spam.guard.caspershouse.com
"Thomas Tomiczek" <t.tom...@thona-consulting.com> wrote in message
news:uXAUyc4P...@TK2MSFTNGP14.phx.gbl...
I've been curious about this problem although I haven't moved to C# 2.0
yet.
An interface is a good idea. Could you not also create a non-qualified
Node type and inherit all Node<T> types from that? Then you could say
simply "Node" with no qualification to indicate any type of Node<T>.
Would that also work?
That would be fine as well. Either way would work. However, it the
type definition gets messy that way because you have one property returning
the value as object (on the base), and another returning the type-safe value
(on the derived generic class). With the interface, you don't clutter up
the public face of the type as much.
--
- Nicholas Paldino [.NET/C# MVP]
- m...@spam.guard.caspershouse.com
"Bruce Wood" <bruc...@canada.com> wrote in message
news:1113331276....@z14g2000cwz.googlegroups.com...
So, yes, I can see that an interface is a better way to solve the
problem.
So, if A is Subclass of B
then c<A> is NOT a subclass of c<B>?
This makes a lot of things way more complicated.
Is there a part of the documentation describing this?
It looks like I HAVE to go with this interface thing - personally I must say
I hate this.
Thomas
"Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote in
message news:OFonfp4...@TK2MSFTNGP12.phx.gbl...
The whole point of List<T> is to provide a type-safe list that
guarantees that all of the things in List<Car>, for example, are Cars.
If List<Car> were a subclass of List<Object> then List<Car> would
export of all its methods (such as .Add(Car T)) as well as all of the
methods of List<Object> (such as .Add(Object T)).
Just to make that clear, it would be (conceptually) something like
this:
public class List<Object>
{
public void Add(Object T) { ... }
}
public class List<Car> : List<Object>
{
public void Add(Car T) { ... }
}
Of course, that's junk code... it's just to give you the conceptual
idea. So what would this do? It would mean that List<Car> would export
_two_ Add methods. One that adds a Car to the list, another that adds
an Object to the list (via the base method in List<Object>). So now we
just lost type safety in the list! Now you can add any object you like
to the list, and you can no longer guarantee that the list will always
contain Cars, so you just lost all of the benefit of generics: you
might as well go back to plain old List!
Each type that you build from a generic has no inheritance relationship
to the other types built from that same generic unless you specifically
indicate one. I know it seems illogical at first glance, but
automatically creating such relationships would render generics useless.