How to implement a service locator pattern with base base classes?

I fell into trap 22 and seem to be unable to find a way out. I am trying to implement a simple [Service Locator] [1] represented by the GetInstance method in the following code example. Now the problem is that I get a compiler error in the return statement:

Cannot implicitly convert type 'Cyberspace.SubClass' to 'Cyberspace.BaseClass<T>'

I tried rewriting, so SubClass is a generic class, but then I get a compiler error in the return statement in the DoSomething method.

Is it possible to compile this code while preserving the principles of the Service Locator template that allow me to have an abstract return type in the GetInstace method? Or am I trying to achieve something impossible here?

 namespace Cyberspace { class BaseClass<T> { BaseClass<T> GetInstance() { return new SubClass(); } virtual T DoSomething() { return default(T); } } class SubClass : BaseClass<OtherClass> { public override OtherClass DoSomething() { var other = new OtherClass { Description = "Generics are hard"}; return other; } } class OtherClass { internal string Description { get; set; } } } 

Attempt 2:

 namespace Cyberspace { class BaseClass<T> { static BaseClass<T> GetInstance() // The "Service Locator" method { return new SubClass<T>(); } internal virtual T DoSomething() { return default(T); } } class SubClass<T> : BaseClass<T> where T: OtherClass { internal override T DoSomething() { var other = new OtherClass { Description = "Generics are hard"}; return (T) other; } } class OtherClass { internal string Description { get; set; } } } 

This results in the following error on the line return new SubClass<T>();

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Cyberspace.SubClass<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'Cyberspace.OtherClass'

+4
source share
2 answers

When using a parameter of type T you declare: "I don’t care what type really is. I just need some type, any type in general. Name it T " But in your case, it looks like you want a certain type. Then there is no need for generics.

 class SubClass : BaseClass<OtherClass> { internal override OtherClass DoSomething() { var other = new OtherClass { Description = "Generics are hard"}; return other; } } 

Why does the following not work?

  var other = new OtherClass { Description = "Generics are hard"}; return (T) other; 

Because T can be obtained from OtherClass . You cannot convert OtherClass to a class derived from OtherClass . It makes no sense, and the compiler is smart enough to catch it.

<h / "> Discussion in the comments leads to the following workaround:

 return (BaseClass<T>)(object)new SubClass(); 

Of course, this only works if the types line up at run time.

+1
source

I don’t understand what you are really trying to do, but I can tell you why this compilation error occurs.

All that is returned from this method:

BaseClass<T> GetInstance()

Must be able to handle any type T (because you have no type restrictions). SubClass can only handle one type, not all types. Therefore, you cannot return it.

+3
source

All Articles