异步元组返回是否有等效的 NotNullWhen C# 模式?

问题描述 投票:0回答:3

在具有可空类型的 C# 中,可以实现智能地进行空检查的“TryGet”,例如,

bool TryGetById(int id, [NotNullWhen(returnValue: true)] out MyThing? myThing)

这允许调用者跳过对 out var myThing 的 null 检查。

不幸的是,异步不允许输出参数,并且使用元组返回的模式不允许这种智能的 NotNull 检查(至少,据我所知)。有替代方案吗?

有没有办法在异步元组返回类型上使用“NotNullWhen”等效项,例如,

Task<(bool Ok, [NotNullWhen(returnValue: true)] MyThing? MyThing)> TryGetById(int id)
c# async-await nullable
3个回答
7
投票

还没有针对 value Tuples 的实现。然而!从C#9开始,您可以使用struct

struct(或者更好的
C#10
记录MemberNotNullWhen
)。

MemberNotNullWhenAttribute 类

指定方法或属性将确保列出的 返回时,字段和属性成员具有非空值 指定的返回值条件。

注意:您将需要重新实现所有tupley的优点,例如平等等。

世界上最做作的例子随之而来

#nullable enable public readonly struct Test { [MemberNotNullWhen(returnValue: true, member: nameof(Value))] public bool IsGood => Value != null; public string? Value { get; init; } } public static Task<Test> TryGetAsync() => Task.FromResult(new Test {Value = "bob"}); public static void TestMethod(string bob) => Console.WriteLine(bob);

用法

var result = await TryGetAsync(); if (result.IsGood) TestMethod(result.Value); // <= no warning
    

1
投票
如果您拥有

MyThing

的实施,您可以这样做

public class MyThing { public static readonly MyThing Empty = new(); // all other properties etc }
然后让你的方法签名永远不会返回 null Mything

public async Task<(bool Ok, MyThing MyThing)> TryGetById(int id) { var something = await FindSomething(id); return (something == null) ? (false, MyThing.Empty); : new (true, something); } var result = await TryGetById(420); if(result.Ok) // whatever
    

0
投票
我找到了另一个解决方案,灵感来自@TheGeneral的答案,我认为这会导致更干净的操作,因为您仍然可以使用 is 关键字来模式匹配元组。

泛型类

public class AsyncParseResult<T> : Tuple<bool, T?> { public AsyncParseResult(bool item1, T? item2) : base(item1, item2) { } [MemberNotNullWhen(returnValue: true, member: nameof(Item2))] public new bool Item1 { get { return base.Item1; } } public new T? Item2 { get { return base.Item2; } } }
使用示例

public class Thing { } public static class Test { public static async Task<AsyncParseResult<Thing>> TryParseThingAsync(string value) { if(value == "thing")//you would replace this with your real parsing logic that uses async { return new AsyncParseResult<Thing>(true, new Thing()); } else { return new AsyncParseResult<Thing>(false, null); } } public static async Task ExampleUsage() { if(await TryParseThingAsync("thing") is (true, var thing)) { //thing will not be null here } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.