如何约束泛型方法的嵌套泛型类型

Hol*_*lly 3 c# generics nested-generics generic-constraints

我正在尝试创建一个方法,该方法根据给定的泛型类型从数据库返回数据。

接口:(此定义编译)

public interface IOrderPosition<TOrder, TArticle, TOrderPosition>
  where TOrder : IOrder
  where TArtile : IArticle
  where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
  long? id { get; set; }
  TOrder order { get; set; }
  TArtile article { get; set; }
  List<TOrderPosition> subPositions { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

一个可能的具体实现:(这个定义编译)

public class OrderPosition : IOrderPosition<Order, Article, OrderPosition>
{
  public long? id { get; set; }
  public Order order { get; set; }
  public Article article { get; set; }
  public List<OrderPosition> subPositions { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

试图写一个基于接口的泛型方法:(这个定义不编译)

public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id) 
  where TOrder : IOrder
  where TArticle : IArticle
  where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
  ..
}
Run Code Online (Sandbox Code Playgroud)

错误:

'DataSourceOrder.GetOrderPositionOfOrder<TOrderPosition>()' does not define type parameter 'TOrder'
'DataSourceOrder.GetOrderPositionOfOrder<TOrderPosition>()' does not define type parameter 'TArticle'
The type or namespace name 'TOrder' could not be found (are you missing a using directive or an assembly reference?)
The type or namespace name 'TArticle' could not be found (are you missing a using directive or an assembly reference?)
Run Code Online (Sandbox Code Playgroud)

像这样使用:

List<OrderPosition> positions = GetOrderPositionOfOrder<OrderPosition>(5);
List<TransferOrderPosition> transferPositions = GetOrderPositionOfOrder<TransferOrderPosition>(5);
Run Code Online (Sandbox Code Playgroud)

题:

为什么这是为接口编译,而不是为方法编译?

我预计两者都会起作用,或者两者都会失败。我假设编译器可以从为 TOrderPosition 给出的类型推断出 TOrder 和 TArticle 的类型,该类型定义了文章和订单的具体类型。

我想知道为什么会发生这种情况,以及是否以及如何解决问题而无需明确指定所有类型。

Art*_*aca 5

为什么这是为接口编译,而不是为方法编译?

好吧,你是在接口中声明TOrderand而不是在方法中。TArticleIOrderPositionGetOrderPositionOfOrder

您需要在方法声明中声明这些泛型参数:

public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id)
    where TOrder : IOrder
    where TArticle : IArticle
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

并这样称呼它:

var list = GetOrderPositionOfOrder<Order, Article, OrderPosition>(5);
Run Code Online (Sandbox Code Playgroud)

但是,如果您想像这样调用GetOrderPositionOfOrder

var list = GetOrderPositionOfOrder<OrderPosition>(5);
Run Code Online (Sandbox Code Playgroud)

您可以IOrderPositionTOrderand 中进行协变TArticle

interface IOrderPosition<out TOrder, out TArticle, TOrderPosition>
    where TOrder : IOrder
    where TArticle : IArticle
    where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
    long? id { get; set; }
    TOrder order { get; }
    TArticle Article { get; }
    List<TOrderPosition> subPositions { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

注意OrderandArticle必须是 getter-only 属性(但这些属性 inOrderPosition可以有set访问器)。

和方法:

public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id)
    where TOrderPosition : IOrderPosition<IOrder, IArticle, TOrderPosition>
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

这样做您可以拨打类似GetOrderPositionOfOrder<OrderPosition>(5).