具有标记为异步功能的功能是否有任何副作用,但实际上并没有进行任何等待调用?例如:
public interface IMyInterface
{
Task DoSomethingAsync();
}
public class DoSomething1:IMyInterface
{
public async Task DoSomethingAsync()
{
await getSomethingFromDatabaseAsync();
}
}
public class DoSomething2:IMyInterface
{
public async Task DoSomethingAsync()
{
doSomethingElse();
}
}
IMyInterface由许多类实现,但是对于其中一个类,没有 await 调用。这会引起任何问题吗?
答案 0 :(得分:7)
在具有返回任务的接口方法并且没有等待的情况下(是的,它发生了)。只需删除async
关键字并返回Task.CompletedTask
Task.CompletedTask
属性返回一个任务,该任务的Status
属性设置为RanToCompletion
。
获取已成功完成的任务。
public class DoSomething2:IMyInterface
{
public Task DoSomethingAsync()
{
doSomethingElse();
return Task.CompletedTask;
}
}
是的,有副作用,编译器正在检查IAsyncStateMachine并生成更多的 IL ,此外,将来的开发人员还将使用 ire 查看您的代码。至于其他功能上的区别,我想不到任何方便的地方。
答案 1 :(得分:2)
IMyInterface由许多类实现,但是对于其中一个类,没有等待调用。这会引起任何问题吗?
我要在这里进入危险地区,不同意埃里克·利珀特。在绝大多数情况下,在没有async
的情况下使用await
确实是一个错误,并且编译器警告很有用。我会说这在90%的时间都是正确的。
但是,我想说这种情况是该规则的例外。仅仅删除async
/ await
的问题在于,异常的处理方式非常不同:
public Task DoSomethingAsync()
{
// if doSomethingElse throws, that exception is raised directly;
// it is *not* captured and placed on the returned task!
doSomethingElse();
return Task.CompletedTask;
}
Task
返回方法的预期语义是捕获异常并将其放置在返回的Task
上(至少,非bone-headed异常)。为了保留这些语义,您需要使用async
(并禁止显示警告)或显式的try
/ catch
:
#pragma warning disable 1998
public async Task DoSomethingAsync()
#pragma warning restore 1998
{
doSomethingElse();
}
// or
public Task DoSomethingAsync()
{
try
{
doSomethingElse();
return Task.CompletedTask;
}
catch (Exception ex)
{
return Task.FromException(ex);
}
}
答案 2 :(得分:-2)
在您的情况下,我认为可能存在阻塞主线程的问题(这取决于您是否在乎),并且我认为这不是开发人员想要的。
如果没有任何等待调用,则可以执行以下操作,以免主线程被阻止(> .net 4.0):
create or replace trigger BIM
before insert on TABLE1
for each row
declare
l_id_exists INT;
begin
select CASE WHEN
exists (select 1 from TABLE2 where TABLE2.ID = :new.ID)
THEN 1
ELSE 0 END INTO l_id_exists from dual;
if l_id_exists = 0
then
raise_application_error(-20634, 'Error');
end if;
end;
/
答案 3 :(得分:-3)
标记为异步的方法将以与只会产生一点开销的方式相同的方式工作,因为当将方法标记为异步时,编译器基本上会为该方法生成状态机。(在您的情况下,不会在某些特定方法中使用)< / p>