Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在接口方法调用中忘记'wait'时没有警告_C#_Async Await - Fatal编程技术网

C# 在接口方法调用中忘记'wait'时没有警告

C# 在接口方法调用中忘记'wait'时没有警告,c#,async-await,C#,Async Await,考虑: using System.Threading.Tasks; class Program { static void Main(string[] args) { C c = new C(); c.FooAsync(); // warning CS4014: Because this call is not awaited, execution of the current method continues before the call i

考虑:

using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        C c = new C();
        c.FooAsync(); // warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
        ((I)c).FooAsync(); // No warning
    }
}

class C : I
{
    public async Task FooAsync()
    {
    }
}

interface I
{
    Task FooAsync();
}
如果我直接在
c
对象上调用async方法,我会得到一个编译器警告。这里可能有一个bug,所以我很高兴得到警告

但是,如果对接口方法进行相同的调用,则不会得到警告。在这段代码中很容易让bug溜走


我怎样才能确保我不会犯这个错误?有没有一种模式可以用来保护我自己?

Main不是异步的,所以它不能使用
wait
。这似乎会稍微混淆编译器消息。如果将调用放入实际的异步方法中

static void Main(字符串[]args)
{
Task.Run(异步()=>
{
C=新的C();
c、 fooanc();
((I)c.fooancy();
});
}
……双方都会发出警告

第10行:因为这个调用没有等待,所以在调用完成之前,当前方法的执行将继续。考虑将“Acess”运算符应用到调用的结果。 第11行:因为此调用没有等待,所以在调用完成之前,当前方法的执行将继续。考虑将“Acess”运算符应用到调用的结果。< /P> 编辑:似乎所有在异步方法中返回
Task
的方法都会发出警告,除非您等待或分配它们;注意,我们使用的接口甚至没有提到异步

interface I
{
    Task FooAsync();
}

static void Main(string[] args)
{
    I i = null;

    i.FooAsync();             // Does not warn
    // await i.FooAsync();    // Can't await in a non async method
    var t1 = i.FooAsync();    // Does not warn

    Task.Run(async () =>
    {
       i.FooAsync();          // Warns CS4014
       await i.FooAsync();    // Does not warn
       var t2 = i.FooAsync(); // Does not warn
    });
}

我冒昧地说,不可能在编译级别发出这种警告。为了支持我的观点,请看以下示例:

interface I
{
    Task Foo();
}

class A : I
{
    public Task Foo()
    {
    }
}

class B : I
{
    public async Task Foo()
    {
    }
}

public class Program
{
    private static void Main(string[] args)
    {
        I i;

        if (Console.ReadLine() == "1")
        {
            i = new A();
        }
        else i = new B();

        i.Foo();
    }
}
你的第一个想法可能是:但这是一个荒谬的情况。但是一些使用机制的设计模式(例如工厂方法)以非常动态的方式实例化派生类


那么VS如何知道该方法是否是异步的呢?

我想您可能要求的太多了

interface I
{
    void Foo();
}

class C {} // does not implement I

class Program
{
    static void Main(string[] args)
    {
        C c = new C();
        ((I)c).Foo(); // Generates no compiler warning
    }
}

然而,强制转换发生在运行时,并且在运行时(或在CIL中)没有类似于
async
的内容。编译器将
async Task Foo()
转换为
Task Foo()
,作为co例程的
状态机实现。

此警告的逻辑似乎是:

  • 异步
    方法中,每当调用
    任务
    返回方法时发出警告,但忽略结果
  • 在正常(非
    async
    )方法中,每当调用返回
    async
    方法的
    任务时发出警告,但忽略结果
例如,看看这个(无意义的)代码:

这就是为什么您没有从接口中得到警告:接口方法没有(也不能)标记为
async

我认为这样做的原因是,在旧的
async
之前的代码中,调用
task.ContinueWith()
并忽略其结果是很常见的。如果在本例中也报告了警告,则相对大量的旧正确代码会突然变成警告

当很可能出现错误时,应输出警告。我认为报告的案例比没有报告的案例更有可能是bug。所以对我来说,这种行为是有道理的


如果您想确保不犯此错误,请小心调用
任务
-从非
异步
代码返回方法。

问得好。。。因为不能将接口方法标记为异步,所以我不希望编译器在这种情况下给您警告。也许有人知道R#是否这样做(或者有插件)。ReSharper没有捕捉到它。在构建过程中可以通过运行自定义的“CQL”查询找到它-但是由于
async
是一种编译器技巧,实际上没有编译到IL中,我怀疑它。够疯狂了,您还可以拥有一个接口成员,如
void Foo()
,然后使用
void async Foo()
在类中实现它。没有警告,但是完全出乎意料的行为我假设您可以编写一个简单的代码解析器来查看代码文件,查找表示
{something}.{something}Async
或可能只是
{something}Async
的正则表达式,并确保前面有
wait
。然后,只要您的命名约定是一致的,您就可以将其作为构建过程的一部分。抱怨,我讨厌小心。
Task NonAsyncMethod()
{
    AsyncMethod(); // warnig
    NonAsyncMethod(); // no warning

    return null; // to make the code compile
}

async Task AsyncMethod()
{
    AsyncMethod(); // warning
    NonAsyncMethod(); // warning
}