2

I'd like to add a method to the ILogger interface. For logger types not implementing this function I'd like them do do nothing (or use a default implementation). For those that do, their implementation should be called.

This below doesn't work. Error CS0539

public static class ILoggerExtensions
{
    // no-op default implementation
    public static void Do(this ILogger logger) { }
}
// ... then in some logger implementation
public class SpecialLogger: ILogger
{
    public void ILogger.Do()
    {
        // ...
    }
}

This below works, but is ugly.

public static class ILoggerExtensions
{
    public static void Show(this ILogger logger) 
    {
        var type = logger.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
        var l = logger.GetType().GetField("_logger", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(logger);
        if (l is null) return;
        var ps = l.GetType().GetProperty("Loggers")?.GetValue(l) as IEnumerable;
        if (ps is null) return;
        foreach(var p in ps)
        {
            var specialLogger = p.GetType().GetProperty("Logger")?.GetValue(p) as SpecialLogger;
            if (specialLogger is null) continue;
            specialLogger.Do();
        }
    }
}
Julian
  • 33,915
  • 22
  • 119
  • 174
Adam V. Steele
  • 559
  • 4
  • 18
  • You can't extend an interface in that way in c#. If you want, you could define your own interface that extends `ILogger` - like here: https://stackoverflow.com/a/22493779/2141621 – Camilo Terevinto Aug 02 '21 at 17:03
  • Of course you can extend an interface (at least if you include an implementation). The second code block works, the second answer in your link shows an extension method on an interface. I can easily believe you can't override such a implementation which is what I was trying to do here. – Adam V. Steele Aug 02 '21 at 17:19
  • 2
    Extension methods are just syntax sugar for a regular static method, they're **not** part of the interface in any way, nor classes implementing the interface know about it. That's why you get a compile error. A second interface including the new method (extending the original) is probably a much better option. – Alejandro Aug 02 '21 at 17:25
  • How would this work for this particular library though? Seems pretty difficult? All the library functions depend on an `ILogger`. I don't even create instances directly, I use the factory. Instances of `ILogger` aren't called directly but calls to `ILogger.Log` get dispatched to all attached providers. How you seen any examples of the type of extension I'm trying to do? – Adam V. Steele Aug 02 '21 at 17:37

1 Answers1

2

You could couple generics with extending the ILogger interface to more closely approach what you're after:

public interface ISpecialLogger : ILogger
{
    void Do();
}

public static class ILoggerExtensions
{
    // explicit implementation
    public static void Do<T>(this T logger)
        where T : ISpecialLogger
    {
        logger.Do();
    }

    // no-op default implementation
    public static void Do(this ILogger logger) {
    }
}

// ... then in some logger implementation
public class SpecialLogger : ISpecialLogger, ILogger
{
    public void Do() { }
}
Joel H-T
  • 21
  • 3