I’ve been using generic classes quite a bit over the last few years. However, I had never used a generic method in a non-generic class until today. I had a web service class that was using declaritive attributes to generate the WSDL. I already had a generic class, WebMethod<R>, that I was using as the base class of all my web methods to encapsulate common functionality such as authentication, logging, etc. There were some things that I needed to in the web service class that I did not want to move to the generic web method class. However, I did not want to duplicate that code in each web method of the web service. Here’s the solution, a generic method in a non-generic class. This code has been simplified for demo purposes:
[WebService(Namespace="http://blah.com/SomeWebServices/",
Description="Some web service.")]
public class SomeWebService : System.Web.Services.WebService {
public R Run<R>(WebMethod<R> method) where R : IWebServiceResponse, new() {
method.UserHostAddress = this.Context.Request.UserHostAddress;
if (AppConfig.GetSetting("systemFactoryType").ToLower() == "local") {
method.SystemFactory = new LocalSystemFactory();
}
return method.Run();
}
[WebMethod(Description = "Take Action.")]
public ActionResponse Action(UserToken user, ActionRequest request) {
return Run(new ActionWebMethod(user, request));
}
[WebMethod(Description = "Fiddle.")]
public FiddleResponse Fiddle(UserToken user, FiddleRequest request) {
return Run(new FiddleWebMethod(user, request));
}
}
public abstract class WebMethod<R> where R : IWebServiceResponse, new() {
public SystemFactory SystemFactory {
set { _systemFactory = value; }
}
protected abstract void RunMethod();
public R Run() {
_response = new R();
if (Login()) {
RunMethod();
}
return _response;
}
}
WebMethod initializes SystemFactory to a remoted implementation in the constructor. I wanted to be able to change that to a non-remoted implementation via the web.config. Similarly, I did not want to add Host Address to the WebMethod constructor, but when I am actually calling the web methods from the web service, I do want to record the Host Address. Without the generic method, I would end up duplicating this code in the body of each web method.
Note that I do not have to explicitly provide a type when I am calling Run, the compiler infers it for me.