我可以使用 Task.CompletedTask 来检测虚方法是否被覆盖了吗?
Can I Use Task.CompletedTask to Detect if Virtual Method was Overridden?
我有一个 asp.net 核心 Web 应用程序,它有一个抽象 class 和一个 child classes 可能会或可能不会覆盖的虚拟方法。我想根据它是否被覆盖来执行不同的逻辑,并且想知道下面的检查是否是个好主意:
public abstract class BaseClass
{
public async Task DoSomethingAsync()
{
var task = OverrideMe();
bool wasOverridden = task != Task.CompletedTask;
await task;
if (wasOverridden)
{
//Virtual method was overridden
}
else
{
//Virtual method was not overridden
}
}
protected virtual Task OverrideMe()
{
return Task.CompletedTask;
}
}
我意识到如果 child class returns Task.CompletedTask
它看起来仍然没有被覆盖。但是如果我们忽略这个事实,这个检查会起作用吗?我最关心的是任务的Id
字段。这会改变并可能导致相等比较失败吗?当我测试上面的代码时,它可以工作,但是如果有其他并行任务 运行 等怎么办?
如果在方法没有覆盖的情况下设置私有字段会怎样:
public abstract class BaseClass
{
private bool _notOverwritten;
public async Task DoSomethingAsync()
{
var task = OverrideMe();
await task;
if (!_notOverwritten)
{
//Virtual method was overridden
}
else
{
//Virtual method was not overridden
}
}
protected virtual Task OverrideMe()
{
_notOVerwritten = true;
return Task.CompletedTask;
}
}
编辑:这个解决方案并不完全有效,因为派生的 class 仍然可以像 @Theodor Zoulias 提到的那样调用 base.OverrideMe()
。
您可以在调用 base.OverrideMe()
时抛出异常并在 DoSomethingAsync
中捕获它,但是派生的 class 也可以捕获此异常。
首先,我推荐re-addressing设计。如果可能,当派生 class 覆盖方法时,基 class 不应更改行为。也许基类型应该定义一个 属性 的接口类型,派生类型可以选择设置或保留 null
。最重要的是,从设计的角度来看,“检测是否存在覆盖”是一个巨大的危险信号。
也就是说,在我(将近)25 年的编程生涯中,我曾经做过一次。我的 ConnectedProperties 库有一个验证检查以尝试确保正确使用;连接属性仅适用于被视为引用类型的类型,因此它检查 if the type overrides Equals
作为“类型被视为值类型”的启发式方法。
如果您必须使用这个有问题的设计,那么反射是唯一可行的方法;在该类型层次结构中找到与 OverrideMe
的名称和参数相匹配的方法,然后检查它们的基本定义是否是来自基本类型的 OverrideMe
。
我有一个 asp.net 核心 Web 应用程序,它有一个抽象 class 和一个 child classes 可能会或可能不会覆盖的虚拟方法。我想根据它是否被覆盖来执行不同的逻辑,并且想知道下面的检查是否是个好主意:
public abstract class BaseClass
{
public async Task DoSomethingAsync()
{
var task = OverrideMe();
bool wasOverridden = task != Task.CompletedTask;
await task;
if (wasOverridden)
{
//Virtual method was overridden
}
else
{
//Virtual method was not overridden
}
}
protected virtual Task OverrideMe()
{
return Task.CompletedTask;
}
}
我意识到如果 child class returns Task.CompletedTask
它看起来仍然没有被覆盖。但是如果我们忽略这个事实,这个检查会起作用吗?我最关心的是任务的Id
字段。这会改变并可能导致相等比较失败吗?当我测试上面的代码时,它可以工作,但是如果有其他并行任务 运行 等怎么办?
如果在方法没有覆盖的情况下设置私有字段会怎样:
public abstract class BaseClass
{
private bool _notOverwritten;
public async Task DoSomethingAsync()
{
var task = OverrideMe();
await task;
if (!_notOverwritten)
{
//Virtual method was overridden
}
else
{
//Virtual method was not overridden
}
}
protected virtual Task OverrideMe()
{
_notOVerwritten = true;
return Task.CompletedTask;
}
}
编辑:这个解决方案并不完全有效,因为派生的 class 仍然可以像 @Theodor Zoulias 提到的那样调用 base.OverrideMe()
。
您可以在调用 base.OverrideMe()
时抛出异常并在 DoSomethingAsync
中捕获它,但是派生的 class 也可以捕获此异常。
首先,我推荐re-addressing设计。如果可能,当派生 class 覆盖方法时,基 class 不应更改行为。也许基类型应该定义一个 属性 的接口类型,派生类型可以选择设置或保留 null
。最重要的是,从设计的角度来看,“检测是否存在覆盖”是一个巨大的危险信号。
也就是说,在我(将近)25 年的编程生涯中,我曾经做过一次。我的 ConnectedProperties 库有一个验证检查以尝试确保正确使用;连接属性仅适用于被视为引用类型的类型,因此它检查 if the type overrides Equals
作为“类型被视为值类型”的启发式方法。
如果您必须使用这个有问题的设计,那么反射是唯一可行的方法;在该类型层次结构中找到与 OverrideMe
的名称和参数相匹配的方法,然后检查它们的基本定义是否是来自基本类型的 OverrideMe
。