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

问题描述 投票:1回答:1

我想允许继承,但禁止直接构造任何继承的类。相反,我想强制使用自定义方法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.");
        }
    }
}
c# inheritance constructor proxy-pattern realproxy
1个回答
4
投票

为什么不使用静态工厂函数而不是构造函数?

EG

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.");
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.