Implicit Conversion over a Collection
I ran into a problem this week regarding implicit conversions in C# on collections. While this (using implicit
) may not be our final approach, I wanted to at least finish out the code to offer the team as an option. I boiled down the problem to the following sample case:
I have two classes in my example: one that represents a business object (Foo) and one that represents the client version (View Object) of this business item (FooVO), as defined below...
public class Foo
{
public string Id {get; set;}
public string BusinessInfo {get; set;}
}
public class FooVO
{
public string Id {get; set;}
public static implicit operator FooVO( Foo foo )
{
return new FooVO { Id = 开发者_Python百科foo.Id };
}
}
My problem is when I have a a List of Foo objects and want to convert them to a list of FooVO objects using my implicit operator.
List<Foo> foos = GetListOfBusinessFoos(); // Get business objects to convert
I tried
List<FooVO> fooVOs = foos; // ERROR
and
List<FooVO> fooVOs = (List<FooVO>) foos; // ERROR
and even
List<FooVO> fooVOs = foos.Select( x => x ); // ERROR
I know I can do this in a loop, but I was hoping for straightforward (LINQ?) way to convert the objects in one shot. Any ideas?
Thank you in advance.
Edit Fixed typo in example
A question much like this gets asked almost every day on SO. You can't do this because doing so violates type safety:
List<Giraffe> g = new List<Giraffe>();
List<Animal> a = g; // Should this be legal?
a.Add(new Tiger()); // Nope; we just added a tiger to a list of giraffes.
In C# 4.0 you can implicitly convert from IEnumerable<Giraffe>
to IEnumerable<Animal>
because there is no "Add" method to screw things up. But you can never do a "covariant" conversion like that if the conversion of the element types is user-defined. It has to be a reference or identity conversion.
You'll need to create a second list and copy them over one at a time. Or use the LINQ helper methods like Select and ToList to do that work for you.
The name of the type system concept you want is "covariance"; a covariant relationship is one where you reason "Giraffes are animals therefore sequences of giraffes are sequences of animals". If this subject interests you then you can read about how we added covariance (and contravariance) to C# 4.0 here:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx
Start from the bottom.
The reason your examples don't work is because you are trying to assign an IEnumerable<FooVO>
to a List<FooVO>
. The following should work.
List<FooVO> fooVos = foos.Select<Foo,FooVO>(x => x).ToList();
List<FooVO> d = new List<FooVO>(foos.Select(x => (FooVO)x));
Works for me.
Use ConvertAll Method passing in the static implicit operator FooVO( Foo foo )
as the argument
List<FooVO> fooVOs = foos.ConvertAll<FooVO>(FooVO.FooVO);
精彩评论