具有特定类型的 List 上的 C# 扩展方法
C# Extension method on List with specific type
我有以下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!
编译器说
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>'
但是 FlightRoute
是 BaseModel
类型。如果我将 bar
的类型明确更改为 List<BaseModel> ...
那么问题就消失了。
List<FlightRouteDTO> bar = new List<BaseModel>().ToDTO<FlightRouteDTO>(); //Why does it only work this way?
我是不是遗漏了什么明显的东西?
您可以引入具有约束的第二种类型参数:
public static List<T> ToDTO<T, K>(this List<K> models) where K : BaseModel
{
return Mapper.Map<List<T>>(models);
}
解决这个问题的更好方法可能是像这样更改签名:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
您实际上不需要接受 List
,因为您没有对值执行任何操作 "list-specific",并且 AutoMapper 理解您传递给它的任何 "collection" 类型。 IEnumerable<T>
就足够了,因为它是关于 T
的协变,它现在在你的情况下工作正常:
// works
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>();
这只是预期的行为:您正在尝试将 List<FlightRoute>
用作 List<BaseModel>
,但仅仅因为 FlitghtRoute
继承自 BaseModel
不会使 List<FlitghtRoute>
继承自List<BaseModel>
:它们是完全不同的类型。
相反,您可以利用 Covariance 的使用,使用接口而不是具体类型。
通过将您的方法签名更改为以下内容,您会注意到不会生成编译器错误:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
那是因为 IEnumerable<T>
是一个带有 covariant 类型参数的接口。通过查看 reference source,您会注意到此接口使用 out T
声明为泛型类型参数,这表明 T
是协变的,并且可以在我们使用时替换为任何继承类型使用 IEnumerable<T>
.
我有以下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!
编译器说
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>'
但是 FlightRoute
是 BaseModel
类型。如果我将 bar
的类型明确更改为 List<BaseModel> ...
那么问题就消失了。
List<FlightRouteDTO> bar = new List<BaseModel>().ToDTO<FlightRouteDTO>(); //Why does it only work this way?
我是不是遗漏了什么明显的东西?
您可以引入具有约束的第二种类型参数:
public static List<T> ToDTO<T, K>(this List<K> models) where K : BaseModel
{
return Mapper.Map<List<T>>(models);
}
解决这个问题的更好方法可能是像这样更改签名:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
您实际上不需要接受 List
,因为您没有对值执行任何操作 "list-specific",并且 AutoMapper 理解您传递给它的任何 "collection" 类型。 IEnumerable<T>
就足够了,因为它是关于 T
的协变,它现在在你的情况下工作正常:
// works
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>();
这只是预期的行为:您正在尝试将 List<FlightRoute>
用作 List<BaseModel>
,但仅仅因为 FlitghtRoute
继承自 BaseModel
不会使 List<FlitghtRoute>
继承自List<BaseModel>
:它们是完全不同的类型。
相反,您可以利用 Covariance 的使用,使用接口而不是具体类型。
通过将您的方法签名更改为以下内容,您会注意到不会生成编译器错误:
public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
return Mapper.Map<List<T>>(models);
}
那是因为 IEnumerable<T>
是一个带有 covariant 类型参数的接口。通过查看 reference source,您会注意到此接口使用 out T
声明为泛型类型参数,这表明 T
是协变的,并且可以在我们使用时替换为任何继承类型使用 IEnumerable<T>
.