0

I have an interface that looks like this:

public interface IInterface<T> where T : IParameterType
{
    void InterfaceMethod(T param);
}

And a lot of implementations of this interface, each with a different derived type for T.

I can't change the interface.

Now I want all the implementations to call a common line of code at the beginning of its implementation of InterfaceMethod. Furthermore, if possible, I would like all future implementations of this interface to also call this line of code automatically. If this cannot be done, then the best solution would be the one requiring the least knowledge by people writing future implementations.

This seems like it should be easy, but I can't immediately see how to do it.

Edited: Appreciate everyone who answered this. I kept it abstract, but the use case is actually NServiceBus handlers (and a super old version of NServiceBus). To route messages, NServiceBus uses reflection to locate a class that implements IHandleMessages where MessageType:IMessage. IHandleMessages requires a method Handle(MessageType message). For a large class of messages, I wanted to do some initialization before the handler ran.

So as far as I can tell, each individual handler class has to actually have a method Handle(MessageType message), which rules out solutions involving moving the implementation of the interface into a base class.

However I found that the handler actually is instantiated per message received, so I could derive the handlers from a base class and the constructor would be called for each message. There may well have been better ways of doing that by using NServiceBus capabilities, but I am relatively new to it and using a version so old the documentation isn't always applicable.

0

3 Answers 3

1

I suppose the canonical way to do this would be to derive the implementations from a common base class.

public class InterfaceBase<T> 
{
    // Constructor
    public Interface<T>()
    {
        // Call your common method here ...
        CommonMethod();
    }

    public virtual void InterfaceMethod<T>()
    {
        // ... Or here
        CommonMethod();
    }

    // If you want implementors to provide the CommonMethod implementation ...
    public abstract void CommonMethod();
}

And then in your derived class:

public class Interface<T> : InterfaceBase<T>
{
    public override Interface<T>
    {
        base.Interface<T>();
        // Remainder of implementation goes here.
    }
}

There's nothing in the language spec that I know of that would enforce such a design, however. Implementors can still break the implementation, in all sorts of ways, as they always could.

3
  • I can't use the constructor as the code needs to be called once per InterfaceMethod. I am OK with making the implementors derive from a base class but was hoping to avoid making them have to remember to call base.InterfaceMethod .
    – RJKVictor
    Oct 13, 2022 at 14:52
  • The only other thing I can think of is to use AOP. Something like Fody.Weaver. A weaver can inject the required function call for you, so that your implementors don't have to. See nuget.org/packages/CompileTimeWeaver.Fody Oct 13, 2022 at 15:03
  • Thanks! It turns out the constructor approach will work after all, so my immediate issue is fixed.
    – RJKVictor
    Oct 13, 2022 at 19:26
2

I've added this answer in response to your comment:

I am OK with making the implementors derive from a base class but was hoping to avoid making them have to remember to call base.InterfaceMethod

You can enforce this behavior without requiring derived classes to manually call the base logic. This requires some clever use of public, private and protected logic.

public abstract class InterfaceBase<T> : IInterface<T> where T : IParameterType
{
    // This is public, and it is designed to be the only way to access your logic
    public void InterfaceMethod<T>(T param)
    {
        MyCommonLogic();
        MyDerivedLogic(param);
    }

    // This is private and cannot be changed by derived classes
    private void MyCommonLogic()
    {
        // The common code you want to force everyone to use
    }

    // This is protected, so it cannot be accessed directly by an external consumer
    // This is abstract, so derived classes MUST implement it
    protected abstract void MyDerivedLogic(T param);
}

Notice how the InterfaceMethod<T> forces that MyCommonLogic is called before MyDerivedLogic. Because InterfaceMethod<T> is not virtual, derived classes are not able to override this behavior. In other words, it is now set in stone that when InterfaceMethod<T> gets called, MyCommonLogic will be executed before anything else.

A derived class is able (and in this example required) to define what goes into MyDerivedLogic, but that implementation itself does not need to remember to call the common logic, because it's already automatically taken care of via the InterfaceMethod<T> method body.

The only way a consumer is able to execute the derived logic is by calling InterfaceMethod<T> (public), since it cannot access MyDerivedLogic directly (as it is protected); and using InterfaceMethod<T> inevitably forces the execution of MyCommonLogic before any of MyDerivedLogic.


The only thing that you cannot force is that derived classes actually derive from your base class. Nothing is stopping them from implementing IInterface<T> directly, therefore bypassing the whole MyCommonLogic part.

There are a few ways to respond to this:

  • It's not an issue. The main goal was to not have to repeat the common logic. We choose to trust (the developers of) the derived classes to make the right decision.
  • We trust that the code review process will catch and flag these deviations from the intended approach.
  • Remove the interface, leave only the base class to be available. This ensures that in order to comply with the contract stipulated by your base class, the derived class must also accept the inherent enforcement of the MyCommonLogic implementation in said base class.
1
  • Appreciate it. I added some elaboration in the OP. As far as me personally, it's resolved with the constructor approach.
    – RJKVictor
    Oct 15, 2022 at 1:57
1

You could create a abstract base class implementing the interface, where the implementation calls the common method, and delegates the rest to the derived class:

public class InterfaceBase<T> : IInterface<T> where T : IParameterType
{
    public void InterfaceMethod()
    {
        // Call the common method,
        CommonMethod();
        // And then delegate the rest to the subclass
        InterfaceMethodImpl();
    }

    protected abstract void InterfaceMethodImpl();
}

So sub classes cannot override the InterfaceMethod, and are forced to implement InterfaceMethodImpl.

Note that your interface example is problematic, since it generic method parameter has the same name as the generic class type parameter. It should either be:

public interface IInterface<T> where T : IParameterType
{
    public void InterfaceMethod();
}

or

public interface IInterface<T1> where T1 : IParameterType
{
    public void InterfaceMethod<T2>();
}
1
  • You're right about the interface definition. Editing question to correct the error.
    – RJKVictor
    Oct 13, 2022 at 15:38

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.