我想允许继承,但禁止直接构造任何继承的类。相反,我想强制使用自定义方法New()
。
目标是确保继承类的每个实例都是其自身的透明代理。
在这种情况下,不可能使构造函数private
或internal
。否则,您无法在程序集外部继承该类。
有没有优雅的方法来解决这个问题?我目前的解决方案
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.");
}
}
}
为什么不使用静态工厂函数而不是构造函数?
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.");
}
}