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)
.
Take a look at the errors:
'DataSourceOrder.GetOrderPositionOfOrder()' does not define type parameter 'TOrder' 'DataSourceOrder.GetOrderPositionOfOrder()' does not define type parameter 'TArtile'
You are referring to type parameters that do not exist.
You're supposed to define them in the method, the same way you're defining them in the interface:
public static List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id)
That means calling the method will be kinda ugly:
var positions = GetOrderPositionOfOrder<Order, Position, OrderPosition>(5);
var transferPositions = GetOrderPositionOfOrder<TransferOrder, TransferArticle, TransferOrderPosition>(5);
When you call the method, you must provide all the type parameters, or none (if they can be inferred). That's just the way it is.
In the interface, you define it as a generic accepting 3 types TOrder, TArticle, TOrderPosition
, so you are able to constrain those types.
Your method only defines a single type, TOrderPosition
, and the compiler cannot infer the fact that you need other types from the the constraint where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
in your method definition.
What you need to do is define all the types on your generic method in the same way you did for your interface:
public List<TOrderPosition> GetOrderPositionOfOrder<TOrder, TArticle, TOrderPosition>(long? id)
where TOrder : IOrder
where TArticle : IArticle
where TOrderPosition : IOrderPosition<TOrder, TArticle, TOrderPosition>
{
..
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.