确保对象仅由工厂创建(C#)

时间:2010-09-08 19:45:15

标签: c# new-operator factory

如何确保某个类仅由工厂实例化而不是直接调用 new

编辑:我需要将工厂作为一个单独的类(用于依赖注入),所以我不能使它成为实例化类的静态方法,所以我不能将设为私​​有。

8 个答案:

答案 0 :(得分:22)

如果工厂位于同一个程序集中,并且只需要保护外部程序集实例化该类,则可以将构造函数设置为内部。我知道阻止所有其他类(包括同一程序集中的类)的唯一方法是使实例化的类成为工厂的嵌套私有类,并仅将其作为接口公开。如果类是它自己的工厂(静态工厂方法),那么你可以像其他人提到的那样将构造函数设为私有。

答案 1 :(得分:11)

将其构造函数设为私有,并将类方法作为静态方法提供给类本身。

在大多数情况下,您可以将构造函数设置为内部,允许您将工厂分解为自己的类 - 我发现通常不值得尝试阻止我自己的团队使用new创建实例在班级组装中。

答案 2 :(得分:5)

使构造函数内部并将工厂安置在同一个程序集中。

public MyClass
{
    internal MyClass()
    {
    }
}

在同一个程序集中

public MyClassGenerator
{
    public static CreateMyClass()
    {
        return new MyClass();
    }
}

如果工厂不能在同一个组件中,或者此方法不适合您,请查看Dan's answer

答案 3 :(得分:5)

如果由于某种原因,您需要将工厂和构造的类放在单独的程序集中(这意味着只使用internal将无效),并且您可以确保您的工厂有机会运行首先,你可以这样做:

// In factory assembly:

public class Factory
{
    public Factory()
    {
        token = new object();
        MyClass.StoreCreateToken(token);
    }

    public MyClass Create()
    {
        return new MyClass(token);
    }

    private object token;
}

// In other assembly:

public class MyClass
{
    public static void StoreCreateToken(object token)
    {
        if (token != null) throw new InvalidOperationException(
            "Only one factory can create MyClass.");

        this.token = token;
    }

    public MyClass(object token)
    {
        if (this.token != token) throw new InvalidOperationException(
            "Need an appropriate token to create MyClass.");
    }

    private static object token;
}

是的,这很麻烦且很尴尬。但可能有一些奇怪的情况,这实际上是一个很好的解决方案。

答案 4 :(得分:2)

您可以使用工厂类中的公共构造函数将具体类作为嵌套私有类 - 这样您的工厂就可以创建它们,其他人甚至看不到它们。 无论如何,你从工厂返回一些接口/抽象类,而不是具体类型。 当然,您无法将返回类型转换为客户端代码中的某个具体类型,但首先它是设计错误的标志,其次您可以使用嵌套私有类继承的更具体的接口/抽象类来解决它。

你可以在这里参考Eric Lippert的答案(针对类似的问题): Why Would I Ever Need to Use C# Nested Classes

答案 5 :(得分:1)

它将始终通过调用new somewhere 来创建,但如果您只想在工厂类中进行,则可以将所有构造函数设置为Internal(或Private),并使用Public Static同一类的工厂方法)。

答案 6 :(得分:1)

很多人都提到过使用internal,但是你也可以使你的构造函数受到保护,并派生出一个只有静态工厂方法的类。这并不妨碍其他人做同样的事情,但在限制对构造函数的直接访问方面做得相当不错。

答案 7 :(得分:0)

我不喜欢在类型本身上拥有工厂,特别是如果它是域对象。如果你有一个单独的班级作为工厂(我认为你应该),那么内部。如果工厂位于不同的组件上,请使用InternalVisible属性。

相关问题