Reputation: 14166
Recently, I had an interview question where the problem being displayed was passing a parameter as its interface. Now, I have always been under the impression you must pass concretes because there is no way to know which instantiation to materialize. Additionally, I was always under the impression you "could" return interfaces...but you should return concretes (as well).
Q: Is parameterizing interfaces a bad idea?
Q: Is returning interfaces "okay"?
Q: If more than one exists, how are you going to know which derivation to instantiate?
UPDATE - TO MAKE IT MORE CLEAR
Sorry for the clarifications...
If I send this to the server:
- How will it know which derivation to instantiate? (this should fail...right?)
var customer = { Name: 'Frank The Tank', Orders: [] }
$.get(url, customer, cb);
Versus, if I send this to the server:
- How will it know which derivation to instantiate?
- Does the concrete type follow? (I've never actually checked)
var customer = new InsideSalesCustomer('Frank The Tank', []);
$.get(url, customer, cb);
var customer = new ExternalCustomer('Bilbo Baggins', []);
$.get(url, customer, cb);
CODE EXAMPLE:
public interface ICustomer
{
string Name { get; }
IEnumerable<IOrder> Orders { get; }
}
public interface IOrder
{
IEnumerable<IOrderItem> OrderItems { get; }
}
public interface IOrderItem
{
IEnumerable<IProduct> Products { get; }
}
public interface IProduct
{
string Name { get; }
}
public class CustomersController : ApiController
{
// I was always told Customer & OrderItem should be a concretes
public IEnumerable<IOrderItem> ListOrderItems(ICustomer customer)
{
// Return All OrderItems for all orders
return customer.Orders.SelectMany(o => o.OrderItems);
}
}
Upvotes: 4
Views: 2429
Reputation: 6674
This, as posted, will actually not work at all in WebAPI, and that might have been the goal of the interview question.
Why? The WebAPI model binder will not be able to figure out the runtime type of the given ICustomer
, and thus when you actually enter into the method, you'll see that the ICustomer object is simply null since it was skipped during binding.
I just tried it myself with an ultra-simple example. If I use ICustomer
as my parameter type, it always comes in null.
If I use a Customer
, everything works fine.
You are able to use interfaces as parameters by using custom model binders, by the way, it just doesn't work directly "out of the box". There's plenty of material on how to do that, I won't get into it here.
Upvotes: 0
Reputation: 173
By using interfaces in this scenario you are allowing more code reuse. Any customer that uses the ICustomer
interface will be able to be passed into this method. In addition, any OrderItem that uses IOrderItem
will be able to be iterated through. This gives you many more possible uses for this method than using just USACustomers
and USOrderItem
, which will lock you into those concrete types. By using interfacses, you can pass any customers and iterate through the returned OrderItem.
To answer your questions
Q: Is parameterizing interfaces a bad idea?
No, and it is definitely not a bad idea in your scenario.
Q: Is returning interfaces "okay"?
Yes, returning an interface is just returning any type that implements that interface.
Q: If more than one exists, how are you going to know which derivation to instantiate?
You can gather the type of the object, it will never return your interface.
Type objectType = myObject.GetType();
You can then cast the object if you wish. ref
object result = Convert.ChangeType(input, someOtherObject.GetType());
Upvotes: 2