In .Net ist das Interface System.IServiceProvider eine einfache und elegante Möglichkeit, Dienste von anderen Objekten abzufragen, ohne genau wissen zu müssen – oder gar zu wollen -, wie die Klassenstruktur dahinter aufgebaut ist. Ist das Interface in dieser Klasse implementiert oder in einer anderen? Egal, man fragt IServiceProvider und bekommt eine Instanz dessen, was man angefragt hat.

Soweit die Theorie. In der Praxis vergisst man als Entwickler dann aber vielleicht doch mal, ein weiteres Interface in die Liste aufzunehmen, sobald man es implementiert hat. Oder IServiceProvider wurde ganz uns gar vergessen.

Deshalb hier meine Methode, mit Fallback-Strategie dennoch zum gweünschten Ergebnis zu kommen:

using System;
using System.Diagnostics;

public static class Program
{
  private static T TryGetService<T>(Object potentialServiceProvider) 
    where T : class
  {
    T service;
    IServiceProvider serviceProvider;

    if (potentialServiceProvider == null)
    {
      return (null);
    }
    service = null;
    serviceProvider = potentialServiceProvider
      as IServiceProvider;
    if (serviceProvider != null)
    {
      service = serviceProvider.GetService(typeof(T)) as T;
    }
    if (service == null)
    {
      service = potentialServiceProvider as T;
    }
    return (service);
  }

  public static void Main()
  {
    ClassAB classAB;
    ClassC classC;
    InterfaceA interfaceA;
    InterfaceB interfaceB;
    InterfaceC interfaceC;
    InterfaceD interfaceD;

    classAB = new ClassAB();
    interfaceA = TryGetService<InterfaceA>(classAB);
    Debug.Assert(interfaceA != null);
    interfaceB = TryGetService<InterfaceB>(classAB);
    Debug.Assert(interfaceB != null);
    interfaceC = TryGetService<InterfaceC>(classAB);
    Debug.Assert(interfaceC != null);
    interfaceD = TryGetService<InterfaceD>(classAB);
    Debug.Assert(interfaceD == null);
    classC = new ClassC();
    interfaceC = TryGetService<InterfaceC>(classC);
    Debug.Assert(interfaceC != null);
    interfaceD = TryGetService<InterfaceD>(classC);
    Debug.Assert(interfaceD == null);
  }
}

interface InterfaceA { }

interface InterfaceB { }

interface InterfaceC { }

interface InterfaceD { }

internal class ClassAB : InterfaceA, InterfaceB, IServiceProvider
{
  private ClassC m_ClassC = new ClassC();

  public Object GetService(Type serviceType)
  {
    if (serviceType == typeof(InterfaceA))
    {
      return (this);
    }
    else if (serviceType == typeof(InterfaceC))
    {
      return (this.m_ClassC);
    }
    //We forgot to register InterfaceB here
    return (null);
  }
}

internal class ClassC : InterfaceC { }

Wenn man es dann immer noch nicht bekommt, hat man wenigstens sein Bestes versucht. 😉