I have gotten myself into a catch 22 and cannot seem to find my way out. I’m trying to implement a simple [Service Locator][1], represented by the GetInstance-method in the example code below. Now the problem is I get a compiler error on the return statement saying:
Cannot implicitly convert type 'Cyberspace.SubClass' to 'Cyberspace.BaseClass<T>'
I’ve tried rewriting so that the SubClass is a generic class itself, but then I get compiler error on the return statement in the DoSomething-method.
Can anyone make this code compile, retaining the Service Locator pattern principles which allow me to have an abstract return type in the GetInstace-method? Or am I trying to acheive 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 yields the following error on 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'
When using a type parameter
Tyou declare: “I don’t care what the type actually is. I just need some type, any type at all. Call itT.”. But in your case it looks like you want a specific type. No need for generics, then.Why doesn’t the following work?
Because
Tmight be derived fromOtherClass. You cannot convertOtherClassto a class derived fromOtherClass. Makes no sense and the compiler is smart enough to catch it.The discussion in the comments lead to the following workaround:
Of course, this only works, if the types line up at runtime.