基类中的反射是一个糟糕的设计理念吗?

发布于 2024-07-25 17:06:04 字数 1738 浏览 2 评论 0原文

一般来说,基类中的反射可以达到一些好的和有用的目的,但我在这里遇到了一个进退两难的情况......使用反射,或者在真正应该公开的时候暴露公共工厂类从语义上讲是私有的(即不只是任何人都应该能够使用它们)。 我想这里有一些代码:

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 类必须是公共的,这意味着任何人都可以调用它来创建不应该的实例。

In general reflection in a base class can be put to some good and useful ends, but I have a case here where I'm between a rock and a hard place... Use Reflection, or expose public Factory classes when they really should be private semantically speaking (ie. not just anyone should be able to use them). I suppose some code is in order here:

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

Now, this code works for me, but is it a horrible kludge and/or a really bad idea? The other option is passing in the Factory's type as a type paramater, but then due to visiblity limitations, the Factory class must be public which means anyone can call it to make instances when they shouldn't be.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

狂之美人 2024-08-01 17:06:04

在处理泛型时,您经常必须使用反射。 从这方面来说我认为你很好。

也就是说,我在这里看到两种形式的代码气味。 然而,它们可能是由于代码卫生造成的,所以我只会对它们进行评论:

首先,您的静态属性是通用项目。 我 99.999% 确信这甚至无法编译。 如果确实如此,那就是不好的形式。

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

When dealing with generics, you frequently have to use reflection. In that regard I think you're fine.

That said, I see two forms of code smell here. They may be due to code sanitation, however, so I'll just comment on them:

First, your static property is of a generic item. I'm 99.999% sure this will not even compile. If it does, it's bad form.

Second, you appear are returning a new instance for every call to Bar. This is also considered bad form for a getter. I would instead have a method called CreateBar() or something similar.

甜柠檬 2024-08-01 17:06:04

使用自定义属性也可以更好地处理这种情况,您可以在其中显式定义要使用的类型。

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

This situation is also better handled with custom attributes where you can explicitly define the type to use.

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

Your singleton property now becomes

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;
        }
    }
} 
两仪 2024-08-01 17:06:04

如果可能的话,如果可以的话,我会尽量避免使用反射。

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

维基百科示例(在 Java 中)的说法是,您创建一个工厂接口,您的工厂类实现该接口,然后您的代码中的某些内容会生成您需要的工厂并将其作为工厂接口返回。

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

If it's possible, I'd try to avoid using reflection if you can get away with it.

To do this, you could try using an Abstract Factory pattern to get around the problem of directly exposing a public factory type, depending on your situation.

The way the Wikipedia example puts it (in Java) is that you create a factory interface, which your factory class implements, then you have something in your code generate the factory you need and return it as the factory interface.

Another way of doing this would be to create an abstract class instead of an interface for your abstract factory, then create a static method within this abstract class for returning the type factory you need.

清醇 2024-08-01 17:06:04

仅供参考,以下内容可以减少

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

Just an FYI, the following can be reduced from

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

to

if( typeof( ISingletonFormFactory<TThis> ).IsAssignableFrom( t ) )
    m_factory = Activator.CreateInstance( t ) as ISingletonFormFactory<TThis>;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文