Generics and Inheritance with Collections
I have read a number of other related questions, but still can't quite figure out how to do what we need to do. Use of generics isn't a must, but seems to be the only way we can potentially get what we need. We are in .net 3.5 so we can't use the new .net 4.0 stuff that I believe is related. Assume we have a base class Parent that has some properties and methods. We also have a ParentCollection which currently implements IEnumerable. We have also added additional properties and methods on this class as well.
We now need to inherit from Parent to create a ChildA. However we also need to Inherit from ParentCollection to create ChildACollect开发者_如何学编程ion. We would then have peer classes to ChildA as ChildB and ChildBCollection.
The ChildACollection and ChildBCollection and their items are the only things that are actually instantiated. The Parent stuff is abstract.
There are methods on the ParentCollection as well as Parent that could return subsets of items that meet criteria and also might have been manipulated.
The issue is since these methods are working with items in the collection, we would like the collection returned to be of the type of the descendant. e.g. Call method SomeMethod() that is defined in ParentCollection through an instance of a ChildACollection so the subset return is of type List instead of a List.
Is there a way to achieve this type of functionality?
Example Pseudo Code of what we are trying to do
public class Parent
{
public string PropA { get; set; }
public int PropB { get; set; }
public void DoSomething() { }
}
public class ParentCollection : IEnumerable<Parent>
{
protected List<Parent> _list = new List<Parent>();
public IEnumerator<Parent> GetEnumerator()
{
return _list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public List<Parent> SomeSelectMethod()
{
List<Parent> list = new List<Parent>();
// DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST
return list;
}
}
public class ChildA : Parent
{
public double PropC { get; set; }
public void DoSomethingElse() { }
}
public class ChildACollection : ParentCollection
{
public void SomeChildMethod() { }
}
public class MyTestClass
{
public void Main()
{
ChildACollection myCollection = new ChildACollection();
//HERE IS THE PROBLEM
List<ChildA> childList = myCollection.SomeSelectMethod();
}
}
Basically I want to take advantage of inheritence but not make the user of the ChildACollection have to constantly cast an object ref returned in the list to a ChildA object. I mean that the internal list will have actual ChildA objects and not Parent objects but since the method is in the ParentCollection class it only know that it is an object of Parent or descendant class. Hope this makes sense.
Help?
FOLLOW UP QUESTION : I need to take this heirarchy 1 more level deep (Grandchild) and add a Add method on Parent that will create and Add the approprate object type to the list, i.e. if Add is called on a ChildCollection reference, it should create and add a type of Child and return a reference to that newly created object that is in the list. Possilbe?
You can use generic type parameter constraints:
class ParentCollection<T> where T : Parent {
public List<T> SomeSelectMethod()
{
List<T> list = new List<T>();
// can treat T as Parent here
return list;
}
}
class ChildACollection : ParentCollection<ChildA> {
}
class ChildBCollection : ParentCollection<ChildB> {
}
You may also consider inheriting from System.Collections.ObjectModel.Collection so you don't have to implement IEnumerable.
For the follow up:
My understanding is that you would like to have a parameterless method Add() on the parent collection which creates an instance of type T, adds it to the collection and returns it. One way to do this would be to add an additional constraint on T:
class ParentCollection<T> where T : new(),Parent {
public T Add() {
var item = new T();
Add(item);
return item;
}
}
So, basically you want the person to be able to call SomeSelectMethod and get either List, List, or List?
You can do that with a generic argument and some LINQ.
public List<T> SomeSelectMethod<T>()
where T : Parent
{
return this.Where(x => x.MatchesSomeExpression && x is T).Cast<T>().ToList();
}
You can make ParentCollection a generic class. Try:
public class ParentCollection<T> : IEnumerable<T> where T:Parent
and replace every in that class with .
Then you can make class ChildACollection : ParentCollection<ChildA>
Here's a solution.
public class ParentCollection<T> : IEnumerable<T> where T : Parent
{
protected List<T> _list = new List<T>();
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public virtual List<T> SomeSelectMethod()
{
List<T> list = new List<T>();
// DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST
return list;
}
}
public class ChildACollection : ParentCollection<ChildA>
{
public void SomeChildMethod()
{
}
//You have the method inherited.
}
精彩评论