C#-允许继承,但禁止直接使用构造函数

时间:2019-04-01 15:57:12

标签: c# inheritance constructor proxy-pattern realproxy

我想允许继承,但禁止直接构造任何继承的类。相反,我想强制使用自定义方法New()

目标是确保继承的类的每个实例都是其自身的透明代理。

在这种情况下,不可能使构造函数为privateinternal。否则,您将无法再从程序集外部继承该类。

有什么优雅的方法可以解决这个问题吗?我当前的解决方案:

public abstract class Class<This> : MarshalByRefObject where This : Class<This>
{
    private static bool ShouldThrowOnConstruction = true;
    private static readonly object Lock = new object();

    public static This New()
    {
        lock (Lock)
        {
            ShouldThrowOnConstruction = false;
            var instance = (This)new ClassProxy<This>().GetTransparentProxy();
            ShouldThrowOnConstruction = true;
        }
        return instance;
    }

    protected Class()
    {
        if (ShouldThrowOnConstruction)
        {
            throw new InvalidOperationException("Direct use of the constructor is forbidden. Use New() instead.");
        }
    }
}

1 个答案:

答案 0 :(得分:4)

为什么不使用静态工厂函数代替构造函数?

例如

public abstract class Class<This> : MarshalByRefObject where This : Class<This>
{
    public static Class<This> Build()
    {
        var instance = (This)new ClassProxy<This>().GetTransparentProxy();
    }

    protected Class() 
    {        
    }
}

这是非常难于滥用的,并且没有您需要线程锁定的竞争条件问题。

我想这意味着所有子类也需要将其默认构造函数设为私有。那是您无法控制的吗?

编辑:

如果要保证无法调用它,请使构造函数抛出异常throw new InvalidOperationException("Direct use of the constructor is forbidden. Use Build() instead.");,而您的GetTransparentProxy方法不应调用new来构造对象但是使用FormatterServices.GetUninitializedObject()绕过构造函数。那应该允许创建实例,但是有点代码味道。

类似这样的东西:

public abstract class Class<This> : MarshalByRefObject where This : Class<This>
{
    public static Class<This> Build()
    {
        // Ensure GetTransparentProxy() calls FormatterServices.GetUninitializedObject() to create the object, rather than calling `new`
        var instance = (This)new ClassProxy<This>().GetTransparentProxy();
    }

    protected Class() 
    {
        throw new InvalidOperationException("Direct use of the constructor is forbidden. Use Build() instead.");
    }
}