Reputation: 7867
I realize it is not possible to derive from a generic type parameter, and I understand all the complications that arise if it is allowed.
So my question is, how do I work around this? I am trying to eliminate some duplicate code and the best solution (which is not a solution because it cannot be done) I have come up with would be to do something like this:
public class Proxy<T> : T where T : CommonBaseClass
The reason I would want to do this is to override some methods in the CommonBaseClass
.
Here is some actual code examples from my project:
public class ReportingServiceProxy : ReportingService2010
{
protected override WebResponse GetWebResponse (WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
// Do override stuff here
return response;
}
}
public class ReportingExecutionProxy : ReportExecution2005
{
protected override WebResponse GetWebResponse (WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
// Do override stuff here
return response;
}
}
In the example above the ReportingService2010
& ReportExecution2005
classes both derive from SoapHttpClientProtocol
which derives from HttpWebClientProtocol
. The override methods GetWebResponse
and GetWebRequest
both override methods in HttpWebClientProtocol
and are identical. These methods are where the code duplication exists which I am trying to refactor out.
For completeness, here is some additional code where I implement the code above:
public abstract class SSRSReportBase<T> where T : new()
{
protected T ssrs;
protected abstract void ServiceLogon();
public SSRSReportBase()
{
ServiceLogon();
// Do other common constructor work here.
}
}
// Implementation #1
public class SSRSReportExecution : SSRSReportBase<ReportExecutionProxy>
{
protected override void ServiceLogon()
{
ssrs.LogonUser("LoginName", null, null);
}
// Create additional wrapper methods for ReportExecution2005
}
// Implementation #2
public class SSRSReportingService : SSRSReportBase<ReportingServiceProxy>
{
protected override void ServiceLogon()
{
ssrs.LogonUser("LoginName", null, null);
}
// Create additional wrapper methods for ReportingService2010
}
The only solution I have come up with is not a possible solution, so obviously it's NOT a solution. Here is the bad code:
public class ReportProxy<T> : T where T : HttpWebClientProtocol, new()
{
protected override WebResponse GetWebResponse (WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
return response;
}
}
// Implementation #1
public class SSRSReportExecution : SSRSReportBase<ReportProxy<ReportExecution2005>>
{
}
// Implementation #2
public class SSRSReportingService : SSRSReportBase<ReportProxy<ReportingService2010>>
{
}
Question: So my question is, how can this code be refactored in such a way as to remove the duplicate code (the GetWebRequest
and GetWebResponse
overrides)?
Upvotes: 2
Views: 1939
Reputation: 112382
A solution would be to not use generics at all and to use a factory pattern. Instead of having a generic parameter with the BaseClass
and the new()
constraint. Type everything BaseClass
and provide a factory for new()
. This can be either a full-fleged factory class or a lightweight factory delegate.
public interface IProtocolFactory
{
ProtocolBaseClass Create();
}
public class SomeDerivedProtocolFactory : IProtocolFactory
{
public ProtocolBaseClass Create()
{
return new SomeDerivedProtocol();
}
}
You might even add additional initialization code in the factory.
public class ReportProxy
{
private IProtocolFactory _factory;
public ReportProxy(IProtocolFactory factory)
{
_factory = factory;
}
public void DoSomething()
{
ProtocolBaseClass protocol = _factory.Create();
...
}
}
Using a delegate
private Func<ProtocolBaseClass> _createProtocol;
public ReportProxy(Func<ProtocolBaseClass> createProtocol)
{
_createProtocol= createProtocol;
}
public void DoSomething()
{
ProtocolBaseClass protocol = _createProtocol();
...
}
Upvotes: 1