views:

761

answers:

2

I have a WCF web service that has a method that returns a generic collection. Now, my question is: Should I expose it as ICollection<T>, List<T>, IList<T>, IEnumerable<T> or something else?

I suppose that List<T> is out of the question since I want to avoid CA1002 errors, but the underlying type will be a List<T>.

I am really interested in hearing your takes on this, preferably with a good explanation of why you think what you think.

Thanks in advance

+2  A: 

Keep in mind that errors such as CA1002 are really meant to apply to libraries. A WCF service is not a library, it's an endpoint that's serializing everything over SOAP, REST, etc.

You'll find that if you try to expose an interface such as ICollection<T> or IList<T>, you'll get errors that the type can't be serialized. In fact, List<T> is probably the best choice here. When a proxy gets generated on the client side, it ends up as an array by default, and many if not most people change it to a List<T>, so 90% of the time, no matter how you choose to expose it, that's the type that the client is going to see anyway.

I'll note that it's generally good practice not to "return" a collection at all from a WCF operation or a web service in general. It's more common to create a proxy class that contains the collection you want, and return that, i.e.:

[OperationContract]
OrdersResult GetOrders(OrderRequest request);

Where the proxy class might look like this:

[DataContract]
public class OrdersResult
{
    [DataMember]
    public List<Order> Orders { get; set; }
}

That way if you decide you need to add more data to either the request or the response, you can do so without causing breaking changes to the client.


Addendum: The real issue here with WCF is that WCF doesn't know that a particular type is used only for outbound data. When any class is exposed through a WCF service, WCF assumes that it can be part of either a request or a response, and if it is part of a request, then the type must be concrete and cannot be immutable. That's the reason for all the other silly restrictions like requiring property setters.

You simply have no choice here but to use a concrete, mutable collection type, and in most cases that means either an array or a generic list.

Aaronaught
+1  A: 

In my opinion, service and data contracts that expose sequences should clearly signal that those sequences are immutable, since they are travelling over the wire as DTOs. It doesn't make a lot of sense adding and removing on a sequence that you received from a different tier. Rather, you want to read that data and do something with it.

Given that, I would really prefer to use IEnumerable<T>, but unfortunately, this just doesn't work well with WCF. You can get all sorts of weird errors, particularly when it comes to deferred execution, so (in a WCF context) it's best to stay away from those.

That really only leaves arrays, since they communicate intent best of the remaining options.

Mark Seemann
Agree with the part about immutability, although arrays aren't really any more immutable than generic lists; only the *size* is immutable.
Aaronaught
Yes, I know, which is why I would have preferred IEnumerable, but given that this is not an option, we have to settle for next-best. Arrays are still 'more immutable' than Lists because you can't change the size, so they communicate intent a little bit more clearly... but not by much, I'll grant :)
Mark Seemann
Lol "more immutable". I guess it's as good an explanation as any. :P
Aaronaught