DbSet classes represent database tables
Keep in mind that the DbSet
classes you are defining in your DbContext
represent the tables in your database. The tables are real items with real columns. Every column is represented by a property in the class that you will put in your DbSet
. If columns are not real, and represent a relation, than the property is defined as virtual. You can see this in the virtual declarations in the one-to-many related classes.
The effect is, that the 'DbSetclasses in your
DbContext` are not
interfaces, but real classes.
On the other hand, these classes might implement your interfaces.
Derived interfaces
Your OnlineCustomers
only have OnlineOrders
. You expect that if your ask an OnlineCustomer
for their Orders
that you get the same objects than if you ask them for their OnlineOrders
. So why use a different function name?
But I want a different return value!
If you have derivation in interfaces and a function in your derived interface should do the same as the base function, except for the return value it is more common to use the same function name and use explicit interface implementations.
You see this also in IEnumerable.GetEnumerator()
and IEnumerable<T>.GetEnumerator()
Both functions use the same method name, their return value is different. If you have an IEnumerable<T>
and you ask GetEnumerator()
you know you get an IEnumerator<T>
, which is derived from IEnumerator
.
Another example: a List<T>
implements IList<T>
which derives from IList
. Interface IList<T>
is implemented normally, while IList
is implemented explicitly.
This is very similar to your OnlineUsers
. What you want is, that if you ask an OnlineUser
for their Orders
you expect only OnlineOrders
. After all, OnlineUsers
only have OnlineOrders
. You also want that the returned Orders all have the IOnlineOrders
interface. This interface also implements IOrders
, so if you ask an IOnlineUser
for his Orders
you get his IOnlineOrders
functionality as well as his IOrder
functionality.
This is way more practical then let users decide whether they need to call OnlineOrders
or Orders
So my suggestion would be:
// unchanged:
interface IOrder {...}
interface IOnlineOrder : IOrder {...}
interface IPhoneOrder : IOrder {...}
interface ICustomer {...}
// similar to IEnumerator<T> and IEnumerator
interface IOnlineCustomer : ICustomer
{
new List<IOnlineOrder> Orders { get; set; }
}
interface IPhoneCustomer : ICustomer
{
new List<IPhoneOrder> Orders { get; set; }
}
Note that I use the new
keyword. Whenever I ask an IOnlineCustomer for his Orders
I don't want the 'ICustomer.Orders`.
Class OnlineCustomer
implements both IOnlineCustomer
and ICustomer
. The IOnlineCustomer functions are implements implicitly, the ICustomer functions are implemented explicitly. This function probably will call the implicit Order functions with a Cast.
Try the following:
ICustomer customer = new OnlineCustomer(...);
List<IOrders> orders = customer.Orders();
Your debugger will show you that OnlineCustomers.Orders is called, not the explicitly implemented ICustomer.Orders. Although you only can access the IOrder
functions, all returned elements are in fact IOnlineOrders, which of course implement the
IOrder`.
See also Why implement interface explicitly?
Final remark
You decided to make the return value of your Orders
function a List<IOrder>
. Are your sure that Orders[4]
has a defined meaning in your context?
Wouldn't it be better to return an ICollection<IOrder>', or maybe even an
IReadOnlyCollection? After all the possibility to enumerate and to know the number of elements are key features for your callers. They probably don't want to call
Orders[4]`.
It is fairly difficult to define a proper meaning of Order[4]
, or you would have to do some sorting or something, which is probably a waste of processing power as most callers of your function don't really need a sorted collection.
Consider changing the return value.