我正在尝试创建一个方法,该方法根据给定的泛型类型从数据库返回数据。
界面:(此定义编译)
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的类型,它定义了文章和订单的具体类型。
我想知道为什么会发生这种情况以及我是否以及如何在不必明确指定所有类型的情况下解决问题。
答案 0 :(得分:3)
为什么这会为接口编译,而不是为方法编译?
嗯,您在TOrder
界面中声明了TArticle
和IOrderPosition
,但未在GetOrderPositionOfOrder
方法中声明。
您需要在方法声明中声明这些通用参数:
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
和TOrder
中提出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; }
}
请注意,Order
和Article
必须是仅限getter的属性(但OrderPosition
中的这些属性可以包含set
个访问者。
方法:
public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id)
where TOrderPosition : IOrderPosition<IOrder, IArticle, TOrderPosition>
{
...
}
这样做可以进行GetOrderPositionOfOrder<OrderPosition>(5)
之类的通话。
答案 1 :(得分: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);
调用方法时,必须提供所有类型参数,或者不提供任何类型参数(如果可以推断它们)。这就是它的方式。
答案 2 :(得分: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>
{
..
}