2016-06-08 10 views
3

Ich arbeite an einer Speicher-Caching-Anwendung, die verschiedene Cache-Provider über die Konfiguration laden kann. Ich tue dies, indem ich eine Schnittstelle definiere und ein Plugin-Modell verwende, um eine Assembly und Klasse zu laden, die eine Datei analysiert und eine Klasse lädt, die der Schnittstelle entspricht. Ich würde wirklich gerne die Schnittstelle und mit einem generischen Typ definieren, der jedes Objekt vom Backing-Cache gespeichert werden kann (ob dies ein Wrapper um Drittanbieter-Cache-Client wie Redis oder NCache oder meine eigene MemoryCache-Implementierung ect.) Mit sein Das ultimative Ziel, eine Fabrik zu haben, die ich auf eine DLL verweisen kann, die meine Caching-Methode umschließt.Generics, Interfaces und Activator

Das Problem, das ich in renne, ist Fehler über Generics, wenn ich Activator verwende, um zu versuchen, das Plugin zu instanziieren. Kennt jemand eine Möglichkeit, eine Klasse mit Generics auf eine Schnittstelle zu laden?

Grund Schnittstelle

public interface ICacheProvider<T> 
{ 
    T Get(string key); 
    bool Set(string key, T value, TimeSpan expiration); 
} 

Fabrik ruft

public static ICacheProvider<T> GetCacheProvider(string path, string className, string configuration) 
{    
    ... 
    Assembly asm = Assembly.LoadFile(path); 
    Type type = asm.GetType(className); 

    return Activator.CreateInstance(type, new object[] { configuration }) as ICacheProvider<T>; 
    ... 
} 

Antwort

6

Leider zu laden, aber ich glaube nicht, das gutes Design ist (und ich weiß, dass dies nicht Codereview SE).

ICacheProvider<T> ist nicht sehr brauchbar, weil es nichts gibt, das einen separaten Typ für jedes cachefähige Objekt erfordern würde. Hier finden Sie, IMO, viel besser, und es entlastet Sie von CreateInstance Kopfschmerzen:

public interface ICacheProvider 
{ 
    T Get<T>(string key); 
    bool Set<T>(string key, T value, TimeSpan expiration); 
} 

weiter gehen, ich bin mehr als sicher, dass konkrete Implementierungen von ICacheProvider Arbeit mit einfachen object s, unabhängig von ihrem konkreten Typ.

public interface ICacheProvider 
{ 
    object Get(string key); 
    bool Set(string key, object value, TimeSpan expiration); 
} 

und ein paar Erweiterungsmethoden: Mit diesem können Sie weiter Ihren Vertrag vereinfachen

public static class CacheProviderExtensions 
{ 
    public static T Get<T>(this ICacheProvider cacheProvider, string key); 
    public static bool Set<T>(this ICacheProvider cacheProvider, string key, 
     T value, TimeSpan expiration); 
} 

nun eine der häufigsten Operationen mit Caches ist „get-oder-add“ Verhalten , die als noch eine Methode auf ICacheProvider ausgedrückt werden kann:

object GetOrSet(string key, Func<object> valueProvider, TimeSpan expiration) 
+0

Sie sind richtig, dass konkrete Implementierungen mit einfachen Objekten arbeiten. Denken Sie daran, die Beispielschnipsel hier sind unglaublich vereinfacht von dem, was sie in Wirklichkeit sind für ein schnelles Beispiel von dem, was ich versuche zu erreichen. Meine Absicht beim Definieren des Typs bei der Initialisierung besteht darin, eine bestimmte Cache-Instanz auf einen bestimmten Typ zu beschränken. Grundsätzlich, wenn ich einen Cache von Benutzerobjekten sage, möchte ich die Möglichkeit einschränken, dass jemand etwas anderes zu dieser Cache-Instanz hinzufügt. Die Erweiterungsmethoden sind keine schlechte Idee, obwohl ich nicht so fehlerresistent bin, wie explizit den Typ des Caches anzugeben. – JMorgan

+0

@ anton-gogolev Warum "Extension" -Methoden verwenden, wenn der Code tatsächlich deins ist? –