I'm trying to create a method which returns data from the database based on the given generic type.
The interface: (this definition compiles)
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; }
}
A possible concrete implementation: (this definition compiles)
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; }
}
Trying to write a generic method based on the interface: (this definition DOES NOT compile)
public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id)
where TOrder : IOrder
where TArticle : IArticle
where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
..
}
Errors:
'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?)
To be used like this:
List<OrderPosition> positions = GetOrderPositionOfOrder<OrderPosition>(5);
List<TransferOrderPosition> transferPositions = GetOrderPositionOfOrder<TransferOrderPosition>(5);
Question:
Why does this compile for the interface, but not for the method?
I expected both to work or both to fail. I assumed that the compile could infer the types of TOrder and TArticle from the type given for TOrderPosition which defines concrete types for both the article and order.
I would like to know why this happens and if and how I can solve the problem without having to specify all types explicitly.
Why does this compile for the interface, but not for the method?
Well, you are declaring TOrder
and TArticle
in IOrderPosition
interface but not in GetOrderPositionOfOrder
method.
You need to declare these generic parameters in method declaration:
public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id)
where TOrder : IOrder
where TArticle : IArticle
where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
...
}
And call it like this:
var list = GetOrderPositionOfOrder<Order, Article, OrderPosition>(5);
But if you want to call GetOrderPositionOfOrder
like:
var list = GetOrderPositionOfOrder<OrderPosition>(5);
You can make IOrderPosition
covariant in TOrder
and 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; }
}
Note that Order
and Article
must be getter-only properties (but these properties in OrderPosition
can have set
accessor).
And the method:
public List<TOrderPosition> GetOrderPositionOfOrder<TOrderPosition>(long? id)
where TOrderPosition : IOrderPosition<IOrder, IArticle, TOrderPosition>
{
...
}
Doing this you can make the calls like GetOrderPositionOfOrder<OrderPosition>(5)
.