LP13 LP13 - 3 months ago 26
C# Question

Factory method that returns generic instance

I have a base service class with virtual method that sets the properties of an object and returns that object.

Then i have one more service which derived from the base service and also overrides the base method. In overriden method, the derived service executes

base.DowWork()
to set common properties, and then also sets additional properties.

So based on articles here and here I was able to do this using generics.

public interface IResult
{
}

public class BaseResult : IResult
{
public string CommonProperties { get; set; }
}

public class AdditionalResult : BaseResult
{
public string AdditionalProperties { get; set; }
}

public interface IService<T> where T : IResult
{
T DoWork();
}

public class BaseService<T> : IService<T> where T : BaseResult, new()
{
public virtual T DoWork()
{
var t = new T();

t.CommonProperties = "Some Value";

return t;
}
}
public class AdditionalService : BaseService<AdditionalResult>
{
public override AdditionalResult DoWork()
{
var addtionalResult = base.DoWork();

addtionalResult.CommonProperties = "Override value that was set by BaseService";
addtionalResult.AdditionalProperties = "Set additional properties";

return addtionalResult;
}
}


So far so good

Now i want to create a Factory method that will return the instance of a service based on some type. The application will use the factory to get service instance and call DoWork() like below

class Program
{
static void Main()
{
var factory = new MyFactory();
var service = factory.GetService(0);
var iresult = service.DoWork();

// do something here with IResult
}
}


below is the factory method

public class MyFactory
{
public IService<IResult> GetService(int someType)
{
if (someType == 0)
{
return (IService<IResult>)new BaseService<BaseResult>();
}

if (someType == 1)
{
return (IService<IResult>)new AdditionalService();
}

// note I may have more types and services here. But for simplicity i am using only 2

throw new NotSupportedException();
}
}


However i am not able to figure out what should be the signature of this factory method? Based on suggestions here I'm casting service instance but while executing the application I am getting runtime exception


Unable to cast object of type
'BaseService 1[BaseResult]' to
type 'IService 1[IResult]'


if i don't cast the service instance in the Factory then i get compile time error


Cannot implicitly convert type 'BaseService' to
'IService'. An explicit conversion exists (are you missing a
cast?)

Answer

See SO question Understanding Covariant and Contravariant interfaces in C#.

You want to use covariance (out keyword). If you add it to your IService interface generic type it works as expected.

public interface IService<out T> where T : IResult

I know SO prefers not to post links but I can't possibly write anything more or better than already answered in that question.

Comments