Frage

Zur Zeit habe ich meine VaryByCustom Funktionalität in Klassen implementiert, die eine Schnittstelle IOutputCacheVaryByCustom

implementieren
public interface IOutputCacheVaryByCustom
{
    string CacheKey { get; }
    HttpContext Context { get; }
}

Eine Klasse diese Schnittstelle implementiert hat ein paar Konventionen der Name der Klasse „OutputCacheVaryBy_______“ sein, wo der Zuschnitt der Wert ist, der in der VaryByCustom Eigenschaft übergeben wird, auf den Seiten. Die andere Konvention ist, dass Kontext wird durch Konstruktor Injektion eingestellt werden.

Ich bin stützen diese Zeit aus einer Enum und einer switch-Anweisung ähnlich wie

public override string GetVaryByCustomString(HttpContext context, 
                                              string varyByCustomTypeArg)
{
    //for a POST request (postback) force to return back a non cached output
    if (context.Request.RequestType.Equals("POST"))
    {
        return "post" + DateTime.Now.Ticks;
    }
    var varyByCustomType = EnumerationParser.Parse<VaryByCustomType?>
                            (varyByCustomTypeArg).GetValueOrDefault();


    IOutputCacheVaryByCustom varyByCustom;
    switch (varyByCustomType)
    {
        case VaryByCustomType.IsAuthenticated:
            varyByCustom = new OutputCacheVaryByIsAuthenticated(context);
            break;
        case VaryByCustomType.Roles:
            varyByCustom = new OutputCacheVaryByRoles(context);
            break;
        default:
            throw new ArgumentOutOfRangeException("varyByCustomTypeArg");
    }

    return context.Request.Url.Scheme + varyByCustom.CacheKey;
}

Da ich weiß immer, dass die Klasse OutputCacheVaryBy + varyByCustomTypeArg sein wird und die einzige Konstruktorargument context wird mir klar, ich konnte Bypass, um diese, wenn auch Block verherrlichte und konnte nur mit Activator meinem eigenen Objekt instanziiert.

Mit diesem wird gesagt, Reflexion ist nicht meine Stärke und ich weiß, dass Activator wesentlich langsamer vergleichsweise statische Schöpfung und andere Möglichkeiten, um Objekte zu erzeugen. Gibt es einen Grund, warum ich mit diesem aktuellen Code bleiben soll oder ich Activator oder eine ähnliche Art und Weise verwenden, um mein Objekt zu erstellen?

Ich habe den Blog gesehen http://www.smelser.net/blog/post/2010/03/05/When-Activator-is-just-to-slow.aspx aber ich bin nicht wirklich sicher, wie dies würde gelten, da ich mit Typen zur Laufzeit nicht statisch T arbeitete.

War es hilfreich?

Lösung

Sie haben nicht wirklich brauchen, um Reflektion verwenden, da es sich um eine eher begrenzte Menge der möglichen Werte ist. Sie könnten jedoch so etwas wie dieses

tun
internal class Factory<T,Arg>
{
   Dictionary<string,Func<Arg.T>> _creators;
   public Factory(IDictionary<string,Func<Arg,T>> creators)
  {
     _creators = creators;
  }
}

und ersetzen Sie Ihre Kreation Logik mit

_factory[varyByCustomTypeArg](context);

es ist nicht so schnell wie ein Schalter, aber es hält Aufbau und die Verwendung schön seperate

Andere Tipps

Wenn Reflexion für Sie zu langsam ist. Sie können sich wahrscheinlich Ihre eigenen Objectarbeits bekommen. Es ist wirklich einfach. Fügen Sie einfach eine neue Methode, um Ihre Schnittstelle.

    public interface IOutputCacheVaryByCustom
    {
        string CacheKey { get; }
        IOutputCacheVaryByCustom NewObject();
    }

als eine statische erstellen Nur-Lese-CloneDictionary, die die Objektvorlagen enthält.

    static readonly
        Dictionary<VaryByCustomType, IOutputCacheVaryByCustom> cloneDictionary
        = new Dictionary<VaryByCustomType, IOutputCacheVaryByCustom>
        {
            {VaryByCustomType.IsAuthenticated, new OutputCacheVaryByIsAuthenticated{}},
            {VaryByCustomType.Roles, new OutputCacheVaryByRoles{}},
        };

Wenn Sie damit fertig sind, können Sie die ENUM nutzen, dass Sie bereits haben, um die Vorlage im Wörterbuch wählen und rufen NewObject ()

        IOutputCacheVaryByCustom result = 
             cloneDictionary[VaryByCustomType.IsAuthenticated].NewObject();

Ist nur so einfach. Die NewObject () Methode, die Sie umsetzen müssen, wird eine neue Instanz zurückkehren, indem Sie das Objekt direkt zu erstellen.

    public class OutputCacheVaryByIsAuthenticated: IOutputCacheVaryByCustom
    {
        public IOutputCacheVaryByCustom NewObject() 
        {
            return new OutputCacheVaryByIsAuthenticated(); 
        }
    }

Das ist alles, was Sie benötigen. Und es ist unglaublich schnell.

Ich mag wirklich Objekterstellung Pflege von jemand anderem machen lassen. Zum Beispiel, wenn ich brauche verschiedene konkrete Implementierungen einer Schnittstelle ein IoC-Container hat Wunder für mich gearbeitet.

Als ein einfaches Beispiel Einheit verwendete, haben Sie einen Teil Konfigurationsschlüssel auf Implementierungen Verknüpfung wie folgt:

public void Register(IUnityContainer container)
{
   container.RegisterType<IOutputCacheVaryByCustom,OutputCacheVaryByIsAuthenticated>("auth");
   container.RegisterType<IOutputCacheVaryByCustom,OutputCacheVaryByRoles>("roles");
}

und Ihre Kreation aussehen würde viel einfacher in etwa so:

//injected in some form
private readonly IUnityContainer _container;

public override string GetVaryByCustomString(HttpContext context, 
                                              string varyByCustomTypeArg)
{
    //for a POST request (postback) force to return back a non cached output
    if (context.Request.RequestType.Equals("POST"))
    {
        return "post" + DateTime.Now.Ticks;
    }
    try
    {
    IOutputCacheVaryByCustom varyByCustom = _container.Resolve<IOutputCacheVaryByCustom>(varyByCustomTypeArg, new DependencyOverride<HttpContext>(context));
    }
    catch(Exception exc)
    {
       throw new ArgumentOutOfRangeException("varyByCustomTypeArg", exc);
    }
    return context.Request.Url.Scheme + varyByCustom.CacheKey;
}

Oder wenn IoC ist keine Option i eine Fabrik, die konkreten Klassen erstellen lassen würde, so müssen Sie nie Ihre eigentlichen Methoden um sie kümmern.

Bleiben Sie mit der switch-Anweisung. Wenn Sie nur ein paar mögliche Fälle wie diese haben, dann versuchen Sie einfach klug Abstraktion zu verwenden, um zu vermeiden Hinsetzen und bekommen die harten Teile des Programms Arbeits ...

Das heißt, aus Ihrer Frage scheint es für Sie, die Activator Macht Arbeit verwenden. Haben Sie es getestet? War es wirklich zu langsam?

Alternativ könnten Sie einfach eine Reihe von Factory-Methoden in einem Dictionary<string, Func<IOutputCacheVaryByCustom> halten. Das würde ich verwenden, wenn Sie diese Objekte oft erstellen (in einer Schleife). Sie könnten dann optimieren auch die string Schlüssel zu Ihrem enum und mit der Umstellung erfolgen. Möchten Sie mehr abstrakt wird verbergen nur die Absicht dieses Stück Code ...

Hier ist ein Beispiel neues Objekt erstellen

public static object OBJRet(Type vClasseType)
{
    return typeof(cFunctions).GetMethod("ObjectReturner2").MakeGenericMethod(vClasseType).Invoke(null, new object[] { });
}

public static object ObjectReturner2<T>() where T : new()
{
    return new T();
}

Einige Infos:

  • cFunctions ist der Name meiner statische Klasse mit den Funktionen

Auch ein Beispiel, wo ich die Klasse erhalten enthalten ist, in eine Arraylist:

    public static object OBJRet(Type vClasseType, ArrayList tArray, int vIndex)
    {
        return typeof(cFunctions).GetMethod("ObjectReturner").MakeGenericMethod(vClasseType).Invoke(null, new object[] { tArray, vIndex });
    }

    public static object ObjectReturner<T>(ArrayList tArray, int vIndex) where T : new()
    {
        return tArray[vIndex];
    }

Mit Reflexion.

    public override string GetVaryByCustomString(HttpContext context,   
                                          string varyByCustomTypeArg)
    {
        //for a POST request (postback) force to return back a non cached output   
        if (context.Request.RequestType.Equals("POST"))   
        {   
            return "post" + DateTime.Now.Ticks;   
        }

        Type type = Type.GetType("OutputCacheVaryBy" + varyByCustomTypeArg, false)
        if (type == null)
        {
            Console.WriteLine("Failed to find a cache of type " + varyByCustomTypeArg);
            return null;
        }

        var cache = (IOutputCacheVaryByCustom)Activator.CreateInstance(type, new object[]{context});
        return context.Request.Url.Scheme + cache.CacheKey;
    } 

Unter Umständen müssen Sie Präfix Typnamen mit einem Namespace: "My.Name.Space.OutputCacheVaryBy" . Wenn das nicht funktioniert, versuchen Sie, mit einem Montage qualifizierten Namen:

Type.GetType("Name.Space.OutputCacheVaryBy" + varyByCustomTypeArg + ", AssemblyName", false)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top