【问题标题】:Throwing exception in async method with preprocessor directive使用预处理器指令在异步方法中引发异常
【发布时间】:2016-06-22 13:12:26
【问题描述】:

我的任务是清理编译器警告的项目。目前我正在研究用于 ASP.NET 和 Xamarin 解决方案的 cs 文件。我有一个方法:

    public override async SomeReturnTypeItem LoginAsync()
    {
#if __MOBILE__
        throw new NotSupportedException("Windows authentication is not supported in mobile version");
#endif
    //some code
    }

在 Xamarin 解决方案中,我警告说 #endif 下的代码无法访问。如果我用#else 替换#endif 并将#endif 放在方法的末尾,我会收到一条警告,指出方法缺少await 运算符并将同步运行。我怎样才能使这个方法没有警告?

【问题讨论】:

  • 你期待什么?如果设置了__MOBILE__,则代码 无法访问- 一个异常和它之后的任何代码都不会执行。如果您不想收到警告,请删除代码,或使用 #else 指令
  • 如果您收到警告“方法缺少等待运算符”`,您根本不应该有 async 关键字,对于两个版本都去掉它。
  • 假设“某些代码”包含await 是否安全?

标签: c# exception async-await c-preprocessor


【解决方案1】:

最简单的解决办法是

public override async SomeReturnTypeItem LoginAsync()
{
#if __MOBILE__
    throw new NotSupportedException("Windows authentication is not supported in mobile version");
#else
    //some code using await
#endif
}

但这可能不是您想要的行为,因为如果定义了__MOBILE__ ,该方法将返回错误的Task,而不是立即抛出。有时差异会很大,主要是如果您存储 Task 以供以后使用而不是立即等待它(例如,如果您想启动多个任务并让它们同时运行)。

要解决这个问题,您应该将抛出异常的代码放在一个方法中,将异步实现放在另一个方法中:

public override SomeReturnTypeItem LoginAsync()
{
#if __MOBILE__
    throw new NotSupportedException("Windows authentication is not supported in mobile version");
#else
    return LoginAsyncImpl();
#endif
}

private async SomeReturnTypeItem LoginAsync()
{
    //some code using await
} 

当然,如果您根本不使用await,则一开始就不应该将您的方法标记为async

public override omeReturnTypeItem LoginAsync()
{
#if __MOBILE__
    throw new NotSupportedException("Windows authentication is not supported in mobile version");
#else
    //some code not using await
#endif
}

请注意,非异步代码仍然可以返回 Task。例如,如果您实现了一个接口或基类,使某些方法返回任务,这样实现可以真正异步,但您的具体实现恰好是同步的,这将非常有用。

public override Task SomeMethodAsync()
{
    // do some  synchronous stuff
    return Task.FromResutl(true);
}

【讨论】:

  • 我认为这个答案的第二部分是最好的解决方案。
  • 但是第一部分是错误的(或不完整的),因为正如问题中提到的,他已经尝试过了,它给出了不同的警告。
【解决方案2】:

这有点难看,但你可以这样做:

    public override
#if !__MOBILE__
    async
#endif
    SomeReturnTypeItem LoginAsync() {
#if __MOBILE__
    throw new NotSupportedException("Windows authentication is not supported in mobile version");
#else
    //some code
#endif
    }

这是假设您实际上在“某些代码”中的某处有 await 关键字。如果没有,那么您应该删除async

或者,您可以简单地使用 #pragma 指令来抑制警告: #pragma warning

【讨论】:

  • 问题不在于async,而是throw 之后的任何代码 无法访问
  • @PanagiotisKanavos 这意味着要与他的修改一起使用:使用#else...#endif。我进行了编辑以使其更加清晰。
【解决方案3】:

我使用的解决方案是欺骗编译器。

    public override async SomeReturnTypeItem LoginAsync()
    {
#if __MOBILE__
        bool isMobile = true;
        if (isMobile)
        {
            throw new NotSupportedException("Windows authentication is not supported in mobile version");
        }
#endif
        //some async code
    }

Visual Stuidio 说异步代码在启发式上是不可访问的,但编译器是满意的。当然,它有点难看,但它确实有效。不过谢谢你们的帮助)

【讨论】:

    猜你喜欢
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多