I would be certain that this question addresses something that would have been brought up in a previous question, but I was unable to find it.
There is a method in a C# class that takes as a parameter a generic List of a Base Class. I need to pass a list of an inherited class and do not know exactly how to do this. I am getting an error in my attempts. Below is sample code to illustrated this:
public class A
{
public static void MethodC(List<A>)
{
// Do Something here with the list
}
}
public Class B : A
{
// B inherits from A, A is the Base Class
}
// Code utilizing the above method
List<B> listOfB = new List<B>();
A.MethodC( (List<A>) listOfB ); // Error: this does not work
A.MethodC( listOfB.ToList<typeof(A)>() ); // Error: this does not work
A.MethodC( listOfB.ConvertAll<A>(typeof(A)) ); // Error: this does not work
// how can I accomplish this? It should be possible I would think
Note: Here is my final working Method as a reference. I got an even better solution to my problem, but technically it wasn't an answer to the question, since my question was phrased impropertly.
public static DataTable
ObjectCollectionToDataTable<GLIST>
(List<GLIST> ObjectCollection) where GLIST
: BaseBusinessObject
{
DataTable ret = null;
if (ObjectCollection != null)
{
foreach ( var b in ObjectCollection)
{
DataTable dt = b.ToDataTable();
if (ret == null)
ret = dt.Clone();
if (dt.Rows.Count > 0)
ret.Rows.Add(dt.Rows[0].ItemArray);
}
}
return ret;
}
-
If you have linq available you can do
var ListOfA = ListOfB.Cast<A>().ToList();
stephenbayer : I do not think I have linq, but it worked anyway. thank you very much for your quick response.Daniel Earwicker : Possible problem - does MethodC need to modify the list, so that those changes are visible outside of MethodC?Quintin Robinson : Glad it worked! The only reason I believe you have the LINQ extension methods available was the use of ToList in your example.stephenbayer : now, it doesn't need to modify the list, it foreachs through the collection and calls abstract methods on each one.Daniel Earwicker : Then see my updated answer... -
You are addressing the lack of covariance in the current C# version. Here is one way of doing it:
listOfB.Cast<A>();
stephenbayer : this works because ((List)listOfB.Cast()) gives me what I want when I explicitly cast it as a List.Andrew Hare : @tvanfosson - Nice catch! -
You cannot do that. To understand why it is not allowed, imagine what would happen if
Add
was called on aList<Derived>
after it had been cast to aList<Base>
.Also, the answers implying that C# 4.0 will be different are wrong. List will never be modified to allow you to do this. Only
IEnumerable
will - because it does not allow items to be added to the collection.Update: The reason it works in the solution you've gone for is because you're no longer passing the same list. You're creating a whole new list which is a copy of the original. This is why I asked about modifying the list; if
MethodC
makes changes to the number of items on the list, those changes would be made to a copy, not the original list.I think the ideal solution for you is as follows:
public abstract class A { public void MethodC<TItem>(List<TItem> list) where TItem : A { foreach (var item in list) item.CanBeCalled(); } public abstract void CanBeCalled(); } public class B : A { public override void CanBeCalled() { Console.WriteLine("Calling into B"); } } class Program { static void Main(string[] args) { List<B> listOfB = new List<B>(); A a = new B(); a.MethodC(listOfB); } }
Notice how, with this solution, you can pass a
List<B>
directly toMethodC
without needing to do that weird conversion on it first. So no unnecessary copying.The reason this works is because we've told
MethodC
to accept a list of anything that is derived fromA
, instead of insisting that it must be a list ofA
.stephenbayer : I don't think that is true, it works fine. My method call works loops through the collection and acts on abstract (override) methods and properties. I used the code above in a previous response, and it works great. the project is .NET 2.0 with CSC.exe (C#) 3.0 as the compiler.Daniel Earwicker : See update above.Daniel Earwicker : I'm guessing you're having difficulty getting this to work? :)
0 comments:
Post a Comment