我很确定您在使用编译器和泛型来节省一些运行时检查方面并不走运。你不能覆盖不存在的东西,你不能对相同的方法有不同的返回类型。
我不能说我完全理解你的动机,但它具有技术价值。
我的第一次尝试是使用具有非虚拟公共接口的基类,然后使用另一个受保护的虚拟方法 CheckCreatedType,这将允许链中的任何内容在调用基类 Create 之前检查类型。
public class A
{
public IFieldSimpleItem Create()
{
IFieldSimpleItem created = InternalCreate();
CheckCreatedType(created);
return created;
}
protected virtual IFieldSimpleItem InternalCreate()
{
return new SimpleImpl();
}
protected virtual void CheckCreatedType(IFieldSimpleItem item)
{
// base class doesn't care. compiler guarantees IFieldSimpleItem
}
}
public class B : A
{
protected override IFieldSimpleItem InternalCreate()
{
// does not call base class.
return new NormalImpl();
}
protected override void CheckCreatedType(IFieldSimpleItem item)
{
base.CheckCreatedType(item);
if (!(item is IFieldNormalItem))
throw new Exception("I need a normal item.");
}
}
以下内容坚持基类的运行时检查。无法解决的问题是您仍然必须依赖被调用的基类方法。行为不端的子类可以通过不调用 base.CheckCreatedType(item) 来破坏所有检查。
替代方法是硬编码基类中所有子类的所有检查(不好),或者以其他方式外部化检查。
尝试 2:(子)类注册他们需要的检查。
public class A
{
public IFieldSimpleItem Create()
{
IFieldSimpleItem created = InternalCreate();
CheckCreatedType(created);
return created;
}
protected virtual IFieldSimpleItem InternalCreate()
{
return new SimpleImpl();
}
private void CheckCreatedType(IFieldSimpleItem item)
{
Type inspect = this.GetType();
bool keepgoing = true;
while (keepgoing)
{
string name = inspect.FullName;
if (CheckDelegateMethods.ContainsKey(name))
{
var checkDelegate = CheckDelegateMethods[name];
if (!checkDelegate(item))
throw new Exception("failed check");
}
if (inspect == typeof(A))
{
keepgoing = false;
}
else
{
inspect = inspect.BaseType;
}
}
}
private static Dictionary<string,Func<IFieldSimpleItem,bool>> CheckDelegateMethods = new Dictionary<string,Func<IFieldSimpleItem,bool>>();
protected static void RegisterCheckOnType(string name, Func<IFieldSimpleItem,bool> checkMethod )
{
CheckDelegateMethods.Add(name, checkMethod);
}
}
public class B : A
{
static B()
{
RegisterCheckOnType(typeof(B).FullName, o => o is IFieldNormalItem);
}
protected override IFieldSimpleItem InternalCreate()
{
// does not call base class.
return new NormalImpl();
}
}
检查是由子类在基类中注册一个要调用的委托来完成的,但基类不需要预先知道所有规则。还要注意,它仍然是非虚拟公共接口,它允许基类在返回结果之前检查结果。
我假设这是您要捕获的开发人员错误。如果适用,您可以使用System.Diagnostics.Conditional("DEBUG")] 修饰运行时检查方法,允许发布版本跳过检查。
我对泛型的了解并不完美,所以这可能是不必要的。然而,这里的检查不必只针对类型:这可以适用于其他用途。例如Register.. 中传递的委托不必只检查引用是否为特定类型'
* 请注意,在上面写的类型名称上创建字典可能不太好;为了说明所使用的机制,这个工作有点简单。