0

I have the following setup:

public interface IRepository<T>
{
    void Save(T entity);
}

public interface IEmailRepository : IRepository<Email> {} // completely empty!

public class MockRepository<T> : IRepository<T> {}

What I wish to do is the following:

void SomeBusinessMethod(IEmailRepository repo) { ... }

MockRepository<Email> mockRepository = CreateMockRepository<Email>();
IEmailRepository mockedEmailRepository = (IEmailRepository) mockRepository; // Invalid cast!
BusinessMethod(mockedEmailRepository);

I am aware that this isn't possible because MockRepository<T> does not inherit from IEmailRepository, even through the class and interface have the exact same signatures.

This is done in a production project and my goal is to inject a mock repository into business classes. I would prefer the possibility of using reflection to forcefully do this conversion anyways to not update the business logic code.

I found that you can use TypeBuilder and ModuleBuilder to create new types and methods with IL, but I just want to assign an interface to an instance that already sort of implements it. Is there a way to achieve this?

There are several other questions slightly related to this problem, but none have been answered with a solution that allows this setup.

Tvde1
  • 1,246
  • 3
  • 21
  • 41
  • 3
    Create a class that inherits `MockRepository` and implements `IEmailRepository`? Or is `MockRepository` instantiated in code you can't change? – CodeCaster Nov 02 '21 at 18:03
  • C# doesn't do [duck typing](https://en.wikipedia.org/wiki/Duck_typing) so there's no way you can force a `MockRepository` to be a `IEmailRepository`, not even via reflection. – DavidG Nov 02 '21 at 18:05
  • Is Save() method the only thing that actually needs replacing? Business method will only call that, as far as I see. Can you use [this](https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method) to replace the EmailRepository's Save() with a new one that will check if it is a "real EmailRepository" and invoke either normal Save() or MockRepository's Save()? You'd have to keep track of the "fake" ones yourself, since they'll think they are real, but that shoud work, no? – defaultUsernameN Nov 02 '21 at 18:47
  • This is possible but it is no easy task. It requires a deep understanding of the DLR, Expressions, Reflection.Emit, and callsite bindings. I would recommend starting your research around the IDynamicMetaObjectProvider. TBH, I worked on something similar about 7 years ago, but ultimately decided it wasn't worth the effort and went with a simpler solution that was supported by the language. – Cobster Nov 02 '21 at 21:00
  • 1
    `Unsafe.As` might be worth a try, but obviously it's unsafe. It may be very much at the whim of the CLR and the Jitter as to whether it crashes your app or not – Charlieface Nov 02 '21 at 21:04

0 Answers0