2009-06-30 60 views
2

一般来说,基类中的反射可以放在一些好的和有用的目的上,但我有一个例子,在岩石和硬地之间......使用反射,或者当公共工厂类实际上暴露时应该是私人语义上的(即不是任何人都应该能够使用它们)。我想一些代码是为了在这里:现在在基础类中反射糟糕的设计理念吗?

public abstract class SingletonForm<TThis> : Form 
    where TThis : SingletonForm<TThis> 
{ 
    private static TThis m_singleton; 
    private static object m_lock = new object(); 
    private static ISingletonFormFactory<TThis> m_factory; 

    protected SingletonForm() { } 

    public static TThis Singleton 
    { 
     get 
     { 
      lock (m_lock) 
      { 
       if (m_factory == null) 
       { 
        foreach (Type t in typeof(TThis).GetNestedTypes(BindingFlags.NonPublic)) 
        { 
         foreach (Type i in t.GetInterfaces()) 
         { 
          if (i == typeof(ISingletonFormFactory<TThis>)) 
           m_factory = (ISingletonFormFactory<TThis>)Activator.CreateInstance(t); 
         } 
        } 

        if (m_factory == null) 
         throw new InvalidOperationException(string.Format(
          CultureInfo.InvariantCulture, 
          "{0} does not implement a nested ISingletonFormFactory<{0}>.", 
          typeof(TThis).ToString())); 
       } 

       if (m_singleton == null || m_singleton.IsDisposed) 
       { 
        m_singleton = m_factory.GetNew(); 
       } 

       return m_singleton; 
      } 
     } 
    } 
} 

,此代码对我的作品,但它是一个可怕的组装机和/或一个非常糟糕的主意?另一种选择是作为类型参数传递工厂类型,但由于可见性限制,Factory类必须是公共的,这意味着任何人都可以调用它来创建实例。

+0

如果你说这是什么试图完成这将有助于。而且,顺便说一句,除了之后检查之外,您可以通过在锁定之前检查null来帮助自己。 – 2009-06-30 01:31:07

+0

这将暗示我想要了解的内容,但请查看“第三版”并告诉我您的想法:http://www.yoda.arachsys.com/csharp/singleton.html – 2009-06-30 01:33:20

+0

编辑,以包括我的实际班 – 2009-06-30 01:34:54

回答

3

在处理泛型时,您经常需要使用反射。在这方面,我认为你很好。

这就是说,我在这里看到两种形式的代码味道。他们可能是由于代码卫生,但是,所以我只是对他们发表评论:

首先,你的静态属性是一个普通的项目。我99.999%肯定这不会编译。如果确实如此,那就是糟糕的形式。

其次,您显示正在为每次致电Bar返回一个新实例。这也被认为是吸气剂的不良形式。相反,我会有一个名为CreateBar()或类似的方法。

0

如果可能的话,我会尽量避免使用反射,如果你能摆脱它。

为此,您可以尝试使用Abstract Factory pattern来解决直接暴露公共工厂类型的问题,具体取决于您的情况。

维基百科的例子(用Java写的)的方式是你创建一个工厂接口,你的工厂类实现了这个接口,然后你的代码中有东西生成你需要的工厂并将它作为工厂接口返回。

这样做的另一种方法是为抽象工厂创建抽象类而不是接口,然后在此抽象类中创建静态方法以返回所需的类型工厂。

0

只是一个供参考,下面可以从

foreach (Type i in t.GetInterfaces()) 
{ 
    if (i == typeof(ISingletonFormFactory<TThis>)) 
     m_factory = (ISingletonFormFactory<TThis>)Activator.CreateInstance(t); 
} 

减少到

if(typeof(ISingletonFormFactory<TThis>).IsAssignableFrom(t)) 
    m_factory = Activator.CreateInstance(t) as ISingletonFormFactory<TThis>; 
1

这种情况也更好地定制属性的处理,你可以明确定义要使用的类型。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
public sealed class SingletonFactoryAttribute : Attribute 
{ 
    public Type FactoryType{get;set;} 
    public SingletonFormAttribute(Type factoryType) 
    { 
     FactoryType = factoryType; 
    } 
} 

你的单属性现在变得

public static TThis Singleton 
{ 
    get 
    { 
     lock (m_lock) 
     { 
      if (m_factory == null) 
      { 
       var attr = Attribute.GetCustomAttribute( 
           typeof(TThis), 
           typeof(SingletonFactoryAttribute)) 
           as SingletonFactoryAttribute; 

       if (attr == null) 
        throw new InvalidOperationException(string.Format(
         CultureInfo.InvariantCulture, 
         "{0} does not have a SingletonFactoryAttribute.", 
         typeof(TThis).ToString())); 

       m_factory = Activator.CreateInstance(attr.FactoryType); 
      } 

      if (m_singleton == null || m_singleton.IsDisposed) 
      { 
       m_singleton = m_factory.GetNew(); 
      } 

      return m_singleton; 
     } 
    } 
}