Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Dependency Injection with Static Methods?

Imagine there is a Customer class with an instance Load() method.

When the Load() method is called, it retrieves order details by e.g.

var orders = Order.GetAll(customerId, ...);

GetAll() is a static method of the Order class and the input parameters are fields defined in the Customer class.

As you can see, Order is a dependency of the Customer class, however, I can't just create an IOrder and inject it there as interfaces can't have static methods.

Therefore, the question is how could I introduce dependency injection in this example?

I don't want to make GetAll() an instance method since it's a static method and need to keep it that way.

For example, I have used utility classes in my design, most of which just contain static methods.

like image 544
The Light Avatar asked Jun 29 '11 15:06

The Light


People also ask

How dependency injection is used in static method?

If you must keep the static method, I would wrap the static calls in a Repository object. interface IOrderRepository { IEnumerable<IOrder> GetAll(customerId, ..); } class OrderRepository : IOrderRepository { IEnumerable<IOrder> GetAll(customerId, ...) { Order. GetAll(customerId,...); // The original static call. } }

Can I use dependency injection with a static class?

You can use dependency injection in a static class using method or property injection. However, you cannot use constructor injection in a static class because the constructor of a static class cannot accept any parameters.

How do you inject a static class service?

You could use Lazy initialization for any object you need to inject to a static class. This would allow you to pass around static objects that can be shared across running instances and other classes/methods that need to use those objects.

What is a static dependency?

Static dependency is a horror keyword in unit testing. If it's our own code, then we can change it. If static calls are forced by the external library or NuGet package, then we actually cannot get away from it. It will always be there, and the best thing we can do is avoid it.


2 Answers

If you must keep the static method, I would wrap the static calls in a Repository object.

Like this:

interface IOrderRepository {
   IEnumerable<IOrder> GetAll(customerId, ..);
}

class OrderRepository : IOrderRepository {
   IEnumerable<IOrder> GetAll(customerId, ...)
   {
     Order.GetAll(customerId,...); // The original static call.
   }
}

Now you inject this repository into your Customer class.

(I'm assuming you're doing this so you can inject fake IOrders at runtime for testing purposes. I should say that in general, static methods are a serious obstacle to testing.)

like image 162
Paul Phillips Avatar answered Sep 22 '22 21:09

Paul Phillips


Seeing as your aggregate root for fetching orders is your customer model I would strongly advise you create a customer repository and inject that to whatever service requires it.

Here is an example:

public class CustomerService
{
    private readonly ICustomerRepository _customerRepository;

    public CustomerService(ICustomerRepository customerRepository)
    {
        if (customerRepository == null)
        {
            throw new ArgumentNullException("customerRepository");
        }

        _customerRepository = customerRepository;
    }

    public IEnumerable<IOrder> GetOrdersForCustomerId(int customerId)
    {
        return _customerRepository.GetOrdersForCustomerId(customerId);
    }
}

public interface ICustomerRepository
{
    IEnumerable<IOrder> GetOrdersForCustomerId(int customerId);
}

class CustomerRepository : ICustomerRepository
{
    public IEnumerable<IOrder> GetOrdersForCustomerId(int customerId)
    {
        throw new NotImplementedException();
    }
}
like image 21
Mike Avatar answered Sep 24 '22 21:09

Mike