I have the following 2 extension methods
namespace Services.Resources.Extensions
{
public static class DataMapExtensions
{
public static T ToDTO<T>(this BaseModel model)
{
return Mapper.Map<T>(model);
}
public static List<T> ToDTO<T>(this List<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
}
}
The first method works perfectly fine.
//Note: FlightRoute inherits BaseModel
FlightRouteDTO foo = new FlightRoute().ToDTO<FlightRouteDTO>(); //This works!
However, the second method does not seem to work.
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>(); //This doesn't work!
The compiler is saying
Error CS1929 'List< FlightRoute>' does not contain a definition for 'ToDTO' and the best extension method overload 'DataMapExtensions.ToDTO< FlightRouteDTO>(List< BaseModel>)' requires a receiver of type 'List< BaseModel>'
But FlightRoute
is of type BaseModel
. If I change the type of bar
to explicitly be List<BaseModel> ...
then the problem goes away.
List<FlightRouteDTO> bar = new List<BaseModel>().ToDTO<FlightRouteDTO>(); //Why does it only work this way?
Am I missing something obvious?
That's just the expected behavior: you are trying to use a List<FlightRoute>
as a List<BaseModel>
, but just because FlitghtRoute
inherits from BaseModel
doesn't make List<FlitghtRoute>
inherit from List<BaseModel>
: they are completely different types.
What you could do, instead, is to leverage the use of Covariance , using interfaces instead of concrete types.
By changing your method signature to the following, you will notice that no compiler error will be generated:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
That's because IEnumerable<T>
is an interface with a covariant type parameter. By looking at the reference source , you will notice that this interface is declared with out T
as generic type parameter, which indicates that T
is covariant, and may be replaced by any inherited type when we use IEnumerable<T>
.
You could introduce a second type parameter with a constraint:
public static List<T> ToDTO<T, K>(this List<K> models) where K : BaseModel
{
return Mapper.Map<List<T>>(models);
}
A better way to solve this might be to change signature like this:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
You don't really need to accept a List
, because you are not doing anything "list-specific" with the value, and AutoMapper understands any "collection" type you pass to it. IEnumerable<T>
is enough, and because it's covariant with respect to T
, it now works fine in your case:
// works
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.