List <String> stringList = null;
List <object> objectList = stringList; //this line causes a compilation error
Error 1 Cannot implicitly convert type 'System.Collections.Generic.List<string>
The generics are all over the place in WCF and you would think that this is always beneficial to all of us. Well, it depends. One of the problems I noticed is that you can not easily handle generic types in a generic way. I know it does not sound good :) but that's what I wanted to say. The best example is ClientBase<T> that is the base class for auto generated proxies. VS.NET generates a proxy type per contract(interface) which might lead to a situation where you need to manage quite a few many different proxies. Let's assume that we use username and password as our authentication method and we want to have a single place where the credentials are set. The method might look like the one below: public void ConfigureProxy(ClientBase<Object> proxy) { proxy.ClientCredentials.UserName.UserName = "u"; proxy.ClientCredentials.UserName.Password = "p"; } Unfortunately we can't pass to that method a proxy of type ClientBase<IMyContract> because of nonvariant nature of C# generics. I can see at least two options how to get around that issue. The first one requires you to clutter the method with a generic parameter despite the fact that there is no use of it.
public void ConfigureProxy <T>(ClientBase <T> proxy) where T : classYou can imagine I'm not big fun of this solution. The second one is based on the idea that the non-generic part of the public interface of ClientBase class is exposed as either a non-generic ClientBase class or a non-generic interface IClientBase. Approach based on a non-generic class:
{
proxy.ClientCredentials.UserName.UserName = "u";
proxy.ClientCredentials.UserName.Password = "p";
}
public abstract class ClientBase : ICommunicationObject, IDisposable
{
public ClientCredentials ClientCredentials
{
//some code goes here
}
}
public abstract class ClientBase <T> : ClientBase where T : class
{
}
Approach based on a non-generic interface:
public interface IClientBase : ICommunicationObject, IDisposable
{
ClientCredentials ClientCredentials { get; }
}
public abstract class ClientBase <T> : IClientBase where T : class
{
}
Having that hierarchy in place we could define our method in the following way:
public void ConfigureProxy(ClientBase/IClientBase proxy)
{
proxy.ClientCredentials.UserName.UserName = "u";
proxy.ClientCredentials.UserName.Password = "p";
}
Unfortunately WCF architects haven't thought about that and a non-generic ClientBase/IClientBase class/interface doesn't exist. The interesting part of this story is that the FaultException<T> class does not suffer from the same problem because there is a non-generic FaultException class that exposes all the non-generic members. The FaultException<T> class basically adds a single property that returns the detail of the fault and that's it. I can find more classes that are implemented in exactly the same way FaultException<T> is implemented. It looks like ClientBase<T> is the only one widely used class that breaks that rule. I would love to see this inconvenience fixed as an extension of C# parameter variance.
C# generics - parameter variance, its constraints and how it affects WCF
ReplyDeleteI agree. I wanted to do a similar thing, except in my case I wanted to provide a common function to close or abort the channel based on state. Sounds like the WCF guys missed this one. Thanks for your ideas though.
ReplyDeletegreat
ReplyDelete