1

I am trying to structure some utility classes to work with collections of rather similar objects. The objects all inherit from one common base class, but of course that does me no good when dealing with collections of those objects. IOW, I can't simply cast a

     List<BaseObject> to List<HigherLevelObject>.

Simplified code as illustration:

class BaseObject {
  int X;
  int Y;
}

class HigherLevelObject : BaseObject {
   ...
}

class AnotherHigherLevelObject : BaseObject {
}

// collections

class HigherLevelCollection : List<HigherLevelObject> {
}

class AnotherHigherLevelCollection : List<AnotherHigherLevelObject> {
}

So both of the collections above do have commonality in their base objects. Now suppose I wanted a generalized function that would operate on both collections. I can't just designate:

public void UtilityFunction(List<BaseObject> param) {
}

and pass in collections of either type above. Is there a simple approach to this?

  • 3
    What does your `UtilityFunction` method need to do? Does it *just* iterate over the collection, or does it modify it? Which version of .NET are you using? And *please* follow naming conventions even for sample code - using unconventional type names makes the code harder to follow. – Jon Skeet Jan 02 '14 at 11:34
  • Well the answer depends upon what your `UtilityFunction` is going to do – Sriram Sakthivel Jan 02 '14 at 11:40
  • 1
    I think you should use generic method with list argument. http://stackoverflow.com/questions/1633690/generic-listt-as-parameter-on-method – mit Jan 02 '14 at 11:49
  • If your BaseObject defines a protected method it you could loop over the List in the UtilityFunction and depending on either it being BaseObject or its child, you could call its version. I don't see why you need the cast the entire collection. – Mukus Jan 02 '14 at 11:54
  • @TejaswiRana But the problem is that there is no `List`, there is only `List`. – svick Jan 02 '14 at 11:58
  • The code, as usual, started off simple. I had originally structured different types of objects/collections for specific data types. Then realized that there was enough commonality that I may be able to inherit from a common base class and eliminate a lot of duplicated code. The short-term goal was fairly simple--to show items that are contained in the base class (read-only). But if I can get this working in some form, I'll be taking a closer look at moving other functions into the more generalized form. Not sure yet if that will be workable. – user3153406 Jan 02 '14 at 12:29
  • @JonSkeet: At present, just iterates, no modifications (covered in other replies). Latest version of .NET. Naming conventions: I tried to make the above easy to follow, but if there are better naming conventions, I'm fine with that. Is this covered somewhere? – user3153406 Jan 02 '14 at 12:38
  • @user3153406: Yes - http://msdn.microsoft.com/en-us/library/ms229002(v=vs.110).aspx – Jon Skeet Jan 02 '14 at 12:39
  • @JonSkeet: Ah, you were referring to capitalizing the names. I thought you were referring to specific names that were used on StackOverflow. Yes, I do normally use Pascal case. I slipped here, but didn't think it was a big deal. I'll try to be more careful. Anyway, I believe svick's reply covers the question. – user3153406 Jan 02 '14 at 14:10

1 Answers1

2

I can see two ways to solve this:

First way would be to use covariance. But that only works on interfaces and even then only on those for which it's safe. Such interfaces include IEnumerable<T> and IReadOnlyList<T> (new in .Net 4.5), both of which are implemented by List<T>.

If one of the interfaces will work for you, then just declare the method using that:

public void UtilityFunction(IEnumerable<baseObject> param)

With that, you will be able to call it with your lists as parameters.

The second option would be to make UtilityFunction() generic with a constraint:

public void UtilityFunction<T>(List<T> param) where T : baseObject

This way, you can call it as UtilityFunction<higherLevelObject>(collection).

You didn't explain what does UtilityFunction() do, so it's hard to tell which of the two options is more suitable, or if you need something else altogether.

BTW, creating a type that inherits from List<T> should be quite rare, you certainly don't need to do it for each type that you want to use in a list, you can use for example List<higherLevelObject> directly.

svick
  • 236,525
  • 50
  • 385
  • 514
  • Thanks. Both approaches seem like they would work. The second seems more versatile, but I haven't used that approach before. As for what UtilityFunction does...I'm trying to keep that open. The immediate application involves something like matrices that are implemented as Lists of Lists, so I was hoping that it would not get too syntactically complex. UtilityFunction, for example, would display debug 'dumps' of the items in the matrix. I may only need to display data (like X and Y in the example) from the base object. – user3153406 Jan 02 '14 at 12:19
  • BTW, I did end up creating classes that inherit from List, for a couple reasons. The classes are actually Lists of Lists, and they get quite ugly and tedious to type. And I was trying to figure ways to collect and organized the related functions. That seemed like the easiest approach. What would you recommend as an alternative? – user3153406 Jan 02 '14 at 14:07
  • @user3153406 For functions that operate on collections, it's common to use extension methods, the whole LINQ is built using those. – svick Jan 02 '14 at 22:01
  • Followup: If you were curious, this was experimental code for doing alignment of genetic data (amino string codes, or DNA/RNA nucleotide string codes). I have been trying to condense the different types of single objects to one common type, with mixed success. I was originally trying to avoid cross-cluttering the different types. IOW, 'weight' relates to aminos but not to nucleotides. Plus, there are different types of alignments. It seems like extension methods would need to apply to the main collection type, so I am not sure how that would work for individual data types. Still working on it. – user3153406 Jan 05 '14 at 05:31