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 的类型作为类型参数传递,但是由于可见性限制,Factory 类必须是公共的,这意味着任何人都可以调用它来创建不应该的实例。

4

4 回答 4

3

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

也就是说,我在这里看到了两种形式的代码异味。然而,它们可能是由于代码卫生问题,所以我只会对它们发表评论:

首先,您的静态属性是通用项目。我有 99.999% 的把握这甚至不会编译。如果是这样,那就是糟糕的形式。

其次,您似乎为每次调用返回一个新实例Bar。对于吸气剂,这也被认为是不好的形式。相反,我会使用一个名为 CreateBar() 或类似的方法。

于 2009-06-30T01:32:52.427 回答
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;
        }
    }
} 
于 2009-06-30T15:10:14.513 回答
0

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

为此,您可以尝试使用抽象工厂模式来解决直接公开公共工厂类型的问题,具体取决于您的情况。

Wikipedia 示例的方式(在 Java 中)是您创建一个工厂接口,您的工厂类实现该接口,然后您的代码中有一些内容生成您需要的工厂并将其作为工厂接口返回。

另一种方法是为你的抽象工厂创建一个抽象类而不是一个接口,然后在这个抽象类中创建一个静态方法来返回你需要的类型工厂。

于 2009-06-30T01:41:40.537 回答
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>;
于 2009-06-30T02:34:16.033 回答