How to pass List<DerivedClass> when param type is List<BaseClass>?
How can i pass a list which is a list of DerivedObjects where the Method is expecting a list of BaseObjects. I am converting the list .ToList<BaseClass>()
and am wondering if there is a better way. My second problem is the syntax is incorrect. I am trying to pass the list byref and i am getting an error: 'ref' argument is not classified as a variable
How can I fix these two problem? thanks.
public class BaseClass { }
public class DerivedClass : BaseClass { }
class Program
{
static void Main(string[] args)
{
List<DerivedClass> myDerivedList = new List<DerivedClass>();
PassList(ref myDerivedList.ToList<BaseClass>());
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable
Console.WriteLine(myDerivedList.Count);
}
public static void PassList(ref List<BaseClass> myList)
{
myList.Add(new DerivedClass());
Console.WriteLine(myList.Count);
}
}
Solved:
A method similar to this has solved my issue.
public static void PassList<T>(ref List<开发者_StackOverflow中文版;T> myList) where T : BaseClass
{
if (myList == null) myList = new List<T>();
// sorry, i know i left this out of the above example.
var x = Activator.CreateInstance(typeof(T), new object[] {}) as T;
myList.Add(x);
Console.WriteLine(myList.Count);
}
Thank you to all who help across this question and from other SO questions.
The ref
part is easy: to pass an argument by reference, it has to be a variable, basically. So you can write:
List<BaseClass> tmp = myDerivedList.ToList<BaseClass>();
PassList(ref tmp);
... but that won't affect either the value of myDerivedList
or contents itself.
The ref
here is pointless anyway, as you're never changing the value of myList
within the method anyway. It's important to understand the difference between changing the value of a parameter and changing the contents of the object that the parameter value refers to. See my article on parameter passing for more details.
Now as for why you can't pass your list in - it's to preserve type safety. Suppose you could do this, and we could write:
List<OtherDerivedClass> list = new List<OtherDerivedClass>();
PassList(list);
Now that would be trying to add an instance of DerivedClass
to a List<OtherDerivedClass>
- that's like adding an apple to a bunch of bananas... it doesn't work! The C# compiler is preventing you from performing that unsafe operation - it won't let you treat a bunch of bananas as a fruit bowl. Suppose we did have Fruit
instead of BaseClass
, and Banana
/ Apple
as two derived classes, with PassList
adding an Apple
to the list it's given:
// This is fine - you can add an apple to a fruit bowl with no problems
List<Fruit> fruitBowl = new List<Fruit>();
PassList(fruitBowl);
// This wouldn't compile because the compiler doesn't "know" that in PassList
// you're only actually adding an apple.
List<Apple> bagOfApples = new List<Apple>();
PassList(bagOfApples);
// This is the dangerous situation, where you'd be trying to really violate
// type safety, inserting a non-Banana into a bunch of bananas. But the compiler
// can't tell the difference between this and the previous one, based only on
// the fact that you're trying to convert a List<Banana or Apple> to List<Fruit>
List<Banana> bunchOfBananas = new List<Banana>();
PassList(bunchOfBananas );
C# 4 allows generic variance in certain situations - but it wouldn't help in this particular case, as you're doing something fundamentally unsafe. Generic variance is a fairly complicated topic though - as you're still learning about how parameter passing works, I would strongly suggest that you leave it alone for the moment, until you're more confident with the rest of the language.
If you must keep the ref
, you can do this:
var list = myDerivedList.ToList<BaseClass>();
PassList(ref list);
// SYNTAX ERROR ABOVE IS - 'ref' argument is not classified as a variable
For a ref
parameter, it needs a variable to reference. When created on-the-fly there's nothing to reference later in code so it really makes no sense.
First, in the code you provided you don't need the ref
because you don't really change the destination (reference) myList in any way.
Then of course you get an error with the ref myDerivedList.ToList<..>()
because with a byref you can change where a variable is pointed to, but you don't give a variable, you give a value (so just read the compiler complain ;) )
To you point: read about Co- and Contravariance - if you are using .net 4.0
精彩评论