Collections with generic objects
There is a method that takes a list of base objects as a parameter.
abstract class Base {}
class MyClass:Base {}
//...
void Method(List<Base> list) {}
When I`m calling that method, I want to pass list of derived objects.
var derivedList = new List<MyClass>();
Method(derivedList);
But I cannot do that because coll开发者_开发技巧ection of derived is not the same as collection of base objects. What is the best practice to handle this situation? Now I'm using my extension .ToBase() where I create new collection, but I think there is nicer solution.
Thanks.
Make your Method
generic:
public void Method<T>(List<T> list) where T : Base
{
//Do your stuff
}
If the method is only reading the values, it could be declared as:
void Method(IEnumerable<Base> list)
that way, your calling code will work fine in C# 4 / .NET 4 without any changes. In .NET 3.5 you could use
Method(derivedList.Cast<Base>());
If your method is adding values to the list, then generic covariance won't and shouldn't work. After all, you wouldn't want a reference to an instance of some other class derived from Base
to be added to your List<MyClass>
, would you?
Making Method
generic (as suggested by Klaus) will work in various situations too, but can also make the code more complicated. It's hard to say whether or not this is a good approach without knowing what your method does... although it's definitely worth trying.
Co-/contra-variance is implemented in C#4.0 which will allow you to directly pass your List<MyClass>
in a method requiring List<Base>
without more work.
In C#3.5, you can use the Cast<T>()
extension method to convert an enumerable of one type to another, which will allow you to convert it to the base type (with the cost of a cast for each entry). It seems that you've already done that with your extension method .ToBase()
The is because List<MyClass>
is not a List<Base>
.
What you can do is:
Method(derivedList.Cast<Base>().ToList());
There isn't a nicer solution, given the existing Method signature. What you're trying to do can be accomplished with primitive arrays, and everyone regrets it. The thing is that if you pass someone a List<Base>
, then it should be allowed for them to place in Base
or anything derived from it. But they can't, because it's really a List<MyClass>
. It would break a lot of things if this were allowed. Making a new collection is the best way to go.
精彩评论