2

I have these interfaces:

public interface _IService<T>
{
    T Get(int id);
    Task<T> SaveAsync(T entity);
    Task<bool> DeleteAsync(int id);
}

public interface ICustomerService : 
    IService<Customer>
{
    IEnumerable<Customer> GetMany(IEnumerable<int> ids);
}

I also have an abstract class and a concrete class:

public abstract class Service : IDisposable
{
    protected readonly IUnitOfWork unitOfWork;

    protected Service(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
    }

    public void Dispose()
    {
        if (unitOfWork != null)
        {
            unitOfWork.Dispose();
        }
    }
}

public class CustomerService : Service, ICustomerService
{ 
    public CustomerService(IUnitOfWork unitOfWork) 
        : base(unitOfWork) 
    { }

    //Implementation here...
}

Everything works as expected.

Now I want to add generic factory pattern to instantiate various services. So I tried to do:

public TService GetService<TService>()
{
    object[] args = new object[] { (unitOfWork) };
    return (TService)Activator.CreateInstance(typeof(TService), args);
}

And used as follows:

var customerService = GetService<ICustomerService>();

However, the following exception is thrown:

Constructor on type 'ICustomerService' not found.

So how can I correctly instantiate a class from the interface?

5
  • You don't create a class instance from the interface. You create a class instance to satisfy the interface. But you still need to explicitly create the class instance (or register the class with some kind of IoC container - but don't do that prematurely). It seems a lot like you are overengineering. Commented Dec 14, 2017 at 9:15
  • 1
    It seems that what you are trying to do is re-invent dependency injection. Look it up, it may well turn out you don't need to build anything yourself. Commented Dec 14, 2017 at 9:17
  • 1
    Or you are reinventing mocking framework like moq. Commented Dec 14, 2017 at 9:23
  • What if you just change 'var customerService = GetService<ICustomerService>();' to 'var customerService = GetService<CustomerService>();'? Commented Dec 14, 2017 at 9:27
  • 1
    @Mirt While that will work, I don't think that's what OP is going for :) Commented Dec 14, 2017 at 9:29

4 Answers 4

7

You cannot. You will need an dependency injection container that knows that for each ISomething you want an ConcreteSomething created. This connection between class and interface is not established magically, just imagine you had two classes implementing ISomething.

You can build that container yourself, using a Dictionary of interface type to class type and then doing return (TService)Activator.CreateInstance(this.TypeMappings[typeof(TService)], args); or you could use one of the existing dependency injection containers. But you need this mapping.

Sign up to request clarification or add additional context in comments.

Comments

1

I want to preface this answer by saying: I'd really recommend using a proper DI container such as Unity, Ninject, or Autofac for this. It looks like you might be trying to reinvent the wheel, and also trying to create the service locator anti-pattern, both of which are potentially bad.

Anyway, to answer your question: You have to create an instance of a concrete implementation.

An interface (ICustomerService) is just a contract that whatever implements it (the concrete implementation - in your case CustomerService) will provide the features defined by that interface.

You need an instance of your concrete class:

private readonly Dictionary<Type, Type> _concreteImplementations = new Dictionary<Type, Type>();

public Factory()
{
    _concreteImplementations.Add(typeof(ICustomerService), typeof(CustomerService));
}

public TService GetService<TService>()
{
    Type toInstantiate;
    if (_concreteImplementations.TryGetValue(typeof(TService), out toInstantiate))
    {
        object[] args = new object[] { (unitOfWork) };
        return (TService)(object)Activator.CreateInstance(toInstantiate, args);   
    }
    else
    {
        return null;
    }
}

Comments

0

You can't instantiate an instance of an interface. You can only instantiate a concrete type (either a class or a struct) that implements the interface.

Comments

0

You cannot. But you could get the same result indirectly by using concrete class.

CustomerService  c = new CustomerService();
ICustomerService i = ((ICustomerService)Activator.CreateInstance(c.GetType()));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.