我有以下2种扩展方法
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);
}
}
}
第一种方法非常好。
//Note: FlightRoute inherits BaseModel
FlightRouteDTO foo = new FlightRoute().ToDTO<FlightRouteDTO>(); //This works!
然而,第二种方法似乎不起作用。
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>(); //This doesn't work!
编译器说
错误CS1929&#39;列表&lt; FlightRoute&GT;&#39;不包含&#39; ToDTO&#39;的定义和最好的扩展方法重载&#39; DataMapExtensions.ToDTO&lt; FlightRouteDTO&gt;(List&lt; BaseModel&gt;)&#39;要求接收器类型为&#39; List&lt; BaseModel&GT;&#39;
但FlightRoute
的类型为BaseModel
。如果我将bar
的类型更改为明确为List<BaseModel> ...
,则问题就会消失。
List<FlightRouteDTO> bar = new List<BaseModel>().ToDTO<FlightRouteDTO>(); //Why does it only work this way?
我错过了一些明显的东西吗?
答案 0 :(得分:5)
这只是预期的行为:您正在尝试将List<FlightRoute>
用作List<BaseModel>
,但仅仅因为FlitghtRoute
继承自BaseModel
而不是{39} ; t List<FlitghtRoute>
继承自List<BaseModel>
:它们是完全不同的类型。
相反,你可以做的是利用Covariance,使用接口而不是具体类型。
通过将方法签名更改为以下内容,您将注意到不会生成编译器错误:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
那是因为IEnumerable<T>
是具有协变类型参数的接口。通过查看reference source,您会注意到此接口使用out T
声明为泛型类型参数,这表示T
是协变的,并且当我们可以替换为任何继承类型使用IEnumerable<T>
。
答案 1 :(得分:3)
您可以引入带约束的第二个类型参数:
public static List<T> ToDTO<T, K>(this List<K> models) where K : BaseModel
{
return Mapper.Map<List<T>>(models);
}
答案 2 :(得分:1)
解决此问题的更好方法可能是更改签名:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
您实际上不需要接受List
,因为您没有使用值执行“特定于列表”的任何操作,并且AutoMapper会理解您传递给它的任何“集合”类型。 IEnumerable<T>
就足够了,因为它与T
有协变性,现在它适用于你的情况:
// works
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>();