The best way to dynamically create classes instead of using a switch block

I currently have a VaryByCustom function implemented in classes that implement the interface IOutputCacheVaryByCustom

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

A class that implements this interface has several conventions, the class name will be "OutputCacheVaryBy_______", where the space is the value that is passed from the variableByCustom property on the pages. Another convention is that the Context will be set via the constructor injection.

I am currently basing this on an enumeration and a switch statement similar to

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;
}

Since I always know that the class will be OutputCacheVaryBy + varyByCustomTypeArg, and the only argument to the constructor will be context, I realized that I could bypass this illustrious if else block and simply create an instance of my own object with Activator.

, , , Activator . , , Activator ?

http://www.smelser.net/blog/post/2010/03/05/When-Activator-is-just-to-slow.aspx, , , T.

+5
6

, . -

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

_factory[varyByCustomTypeArg](context);

, ,

+4

. , ObjectFactory. . .

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

readonly CloneDictionary, .

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

, , , NewObject()

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

. NewObject(), , , .

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

, . .

+6

, - . , , IoC .

, :

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

:

//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;
}

, IoC , factory , .

+3

switch. , , , ...

, , Activator . ? ?

factory Dictionary<string, Func<IOutputCacheVaryByCustom>. , ( ). string enum . , ...

+1

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();
}

:

  • cFunctions - ,

, , 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];
    }
0

.

    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;
    } 

You may need a typename prefix with a namespace: "My.Name.Space.OutputCacheVaryBy" . If this does not work, try giving it a name:

Type.GetType("Name.Space.OutputCacheVaryBy" + varyByCustomTypeArg + ", AssemblyName", false)
0
source

All Articles