views:

149

answers:

5

I have a C# .NET 2.0 project A (class library) that has a form (TreeForm) that uses Tree objects.

I have a project B that has a class Oak that inherits Tree. The class Oak adds some properties to Tree.

class Oak : ProjectA.Tree
{
   public string LeafColor;
}

TreeForm.cs in the class library is a form that has a DataGrid that databinds to a BindingList of Tree objects.

When I try to reference and use the TreeForm in project B with my Oak objects, it's looking for objects of type Tree.

// in project B here.
BindingList<Oak> oaklist = BindingList<Oak>();

private void show_treeform_button_Click(object sender, EventArgs e)
{
   ProjectA.TreeForm tree_form = new ProjectA.TreeForm(oaklist); // this line gives error
   tree_form.Show();
}

I've tried casting the Oak objects to Tree, but I get the error "Cannot convert type Oak to Tree". If I just use the objects in project B as Tree objects it works fine.

How can I use my Oak objects in the TreeForm from project A?

A: 

It seems that you have inherited your Oak from Tree in project B only, so Project A does not know that a Oak inherits from Tree. You should have used a Class Library and both Projects have a reference on it.

Tim Schmelter
Should have been more clear - project A is a class library. See updates.
Dave
A: 

If I'm not mistaking you're trying to access your Oak (from ProjB) which is inherited from Tree (ProjA) from within ProjA?

If so, you'll end up with a circular reference (A > B > A > B > A .. etc etc) and that's a no-go.

riffnl
VS IDE will show this as an error
volody
+3  A: 

You're going to need to post a short but complete code sample to get any meaningful help. But let me venture a guess here.

Is the second project (B) referencing the first project (A)? You have to make sure that the type Tree is actually the same Tree type in both instances. In the example you describe - it sounds like project A actually has a reference to project B - in which case, how does B know about Tree?

If you have the Tree class declared in both projects - it's not the same Tree class.

One project has to reference the Tree class of the other in order for this arrangement to work the way you expect it to.

The general way to organize such projects, is to move the shared classes into a third Class Library assembly, and reference that assembly in both project A and project B. Then you can inherit and consume the types exposed by the class library correctly.

EDIT: So now that you've posted some code, it's possible to give you a more accurate response. It looks like what you're trying to do is pass a generic list of Oak to a method that expects a generic list of Tree. This is not something you can do prior to .NET 4 which supports generic coveriance (on interface types BTW).

In versions of C# prior to 4, you cannot do:

List<Oak> oaklist = new List<Oak>();
List<Tree> treeList = oaklist; // illegal

Just because Oak inherits Tree does not mean that List<Oak> inherits List<Tree>.

You can read more about generic variance at Eric Lippert's blog.

So in your case, if you want to pass a list of Oaks in to TreeForm() you need to pass it in as a list of Tree. Assuming you don't want to change the type of the collection, you can just instantiate an appropriate copy:

ProjectA.TreeForm tree_form = 
       new ProjectA.TreeForm( new List<Tree>( oaklist.Cast<Tree>() ) );     
LBushkin
added some code - project A is a class library and it's using the Tree object from project A.
Dave
+1  A: 

Don't you want to declare the list a BindingList<Tree> then add the Oak instances to it, then pass the BindingList<Tree> objects to A's TreeForm constructor. After all project A can't deal with Oak objects as it doesn't know anything about them, they are defined in project B.

Sam Holder
+2  A: 

The problem is that before .NET 4.0, generics did not support covariance - your TreeForm class expects a BindingList<Tree>, not a BindingList<Oak>. It's a common mistake to think that we can substitute the derived binding list for the base, but we cannot.

Fortunately, we don't need to, because a BindingList<Tree> can contain Oak instances. The solution is to declare your variable like this:

BindingList<Tree> oakList = new BindingList<Tree>();
// Add Oaks, pass to TreeForm

(For brain-bending details, see Eric Lippert's series of articles on variance in C#.)

Jeff Sternal