代码之家  ›  专栏  ›  技术社区  ›  Chris Marisic

动态创建类而不是使用开关块的最佳方法

  •  5
  • Chris Marisic  · 技术社区  · 14 年前

    目前,我在实现接口的类中实现了VaryByCustom功能 IOutputCacheVaryByCustom

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

    一个实现这个接口的类有几个约定,该类的名称将是“OutPuxCaseVARY由Y.Y.Y.Y.Y.*”,其中空白是从页上的ValyByAuto属性传递的值。另一个约定是通过构造函数注入来设置上下文。

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

    因为我一直都知道 OutputCacheVaryBy + varyByCustomTypeArg 唯一的构造函数参数是 context 我意识到我可以绕过这个美化的if-else块,用它来实例化我自己的对象 Activator .

    活化剂 活化剂

    我看过这个博客 http://www.smelser.net/blog/post/2010/03/05/When-Activator-is-just-to-slow.aspx 但我不确定这将如何应用,因为我在运行时使用的是类型,而不是static T。

    6 回复  |  直到 14 年前
        1
  •  4
  •   Rune FS    9 年前

    您不需要真正使用反射,因为它是一组非常有限的可能值。你可以这样做

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

    把你的创造逻辑换成

    _factory[varyByCustomTypeArg](context);
    

    它的速度不如交换机,但它保持建设和使用很好地分开

        2
  •  6
  •   BitKFu    14 年前

    这真的很简单。只需在接口中添加一个新方法。

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

    而不是创建一个保存对象模板的静态只读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(); 
            }
        }
    

        3
  •  3
  •   MrDosu    14 年前

    我真的很喜欢让别人来处理对象创建。例如,如果我需要一个接口的不同的具体实现,一个IoC容器已经为我创造了奇迹。

    作为使用unity的一个简单示例,您有一个配置部分,将键链接到如下实现:

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

        4
  •  1
  •   Daren Thomas    14 年前

    坚持switch语句。如果你只有几个这样的例子,那么你只是在尝试使用巧妙的抽象,以避免坐下来让你的程序的困难部分工作。。。

    也就是说,从你的问题看来 Activator

    或者,您可以将一堆工厂方法保存在 Dictionary<string, Func<IOutputCacheVaryByCustom> . 如果您经常(在一个循环中)创建这些对象,我将使用这个方法。然后还可以优化 string enum 完成转换。变得更抽象只会隐藏这段代码的意图。。。

        5
  •  0
  •   Wildhorn    14 年前

    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是包含函数的静态类的名称

        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];
        }
    
        6
  •  0
  •   jgauffin    14 年前

    使用反射。

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

    您可能需要在typename前面加一个命名空间: . 如果不起作用,请尝试使用程序集限定名:

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