3

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

接口:(此定义编译)

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; }
}

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

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; }
}

尝试基于接口编写通用方法:(此定义不编译)

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

错误:

'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?)

像这样使用:

List<OrderPosition> positions = GetOrderPositionOfOrder<OrderPosition>(5);
List<TransferOrderPosition> transferPositions = GetOrderPositionOfOrder<TransferOrderPosition>(5);

问题:

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

我希望两者都能工作或都失败。我假设编译器可以从给定的 TOrderPosition 类型推断出 TOrder 和 TArticle 的类型,该类型定义了文章和订单的具体类型。

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

4

3 回答 3

5

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

好吧,您是在接口中声明TOrder和,而不是在方法中。TArticleIOrderPositionGetOrderPositionOfOrder

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

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

并这样称呼它:

var list = GetOrderPositionOfOrder<Order, Article, OrderPosition>(5);

但如果你想这样打电话GetOrderPositionOfOrder

var list = GetOrderPositionOfOrder<OrderPosition>(5);

您可以在和中进行IOrderPosition协变:TOrderTArticle

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; }
}

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

和方法:

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

这样做您可以拨打电话GetOrderPositionOfOrder<OrderPosition>(5)

于 2016-11-24T15:57:53.753 回答
2

看看错误:

'DataSourceOrder.GetOrderPositionOfOrder()' 没有定义类型参数 'TOrder' 'DataSourceOrder.GetOrderPositionOfOrder()' 没有定义类型参数 'TArtile'

您指的是不存在的类型参数。
您应该在方法中定义它们,就像在接口中定义它们一样:

public static List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id)

这意味着调用该方法会有点难看:

var positions = GetOrderPositionOfOrder<Order, Position, OrderPosition>(5);
var transferPositions = GetOrderPositionOfOrder<TransferOrder, TransferArticle, TransferOrderPosition>(5);

调用方法时,必须提供所有类型参数,或者不提供(如果可以推断)。就是那样子。

于 2016-11-24T15:54:38.393 回答
0

在接口中,您将其定义为接受 3 种类型的泛型TOrder, TArticle, TOrderPosition,因此您可以约束这些类​​型。

您的方法只定义了一个类型,编译器无法从您的方法定义中TOrderPosition的约束中推断出您需要其他类型的事实。where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>

你需要做的是在你的泛型方法上定义所有类型,就像你为你的接口所做的那样:

public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id) 
 where TOrder : IOrder
 where TArticle : IArticle
 where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
 ..
}
于 2016-11-24T15:54:21.587 回答