是什么 ?[]?C#中的语法?

snr*_*snr 88 .net c# null-coalescing-operator null-coalescing nullable-reference-types

虽然我正在研究委托实际上是一个抽象类中Delegate.cs,我看到了下面的方法中,我不明白

  • 为什么返回值使用?它已经是一个引用()类型
  • ?[]? 参数的含义

你能解释一下吗?

public static Delegate? Combine(params Delegate?[]? delegates)
{
    if (delegates == null || delegates.Length == 0)
        return null;

    Delegate? d = delegates[0];
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}
Run Code Online (Sandbox Code Playgroud)

Ath*_*ras 68

分步说明:

params Delegate?[] delegates - 它是一个可空数组 Delegate

params Delegate?[]? delegates - 整个数组可以为空

由于每个参数都属于该类型Delegate?并且您返回Delegate?[]?数组的索引,因此返回类型是有意义的,Delegate?否则编译器将返回错误,就像您正在int从返回字符串的方法返回一样。

例如,您可以更改代码以返回如下Delegate类型:

public static Delegate Combine(params Delegate?[]? delegates)
{
    Delegate defaulDelegate = // someDelegate here
    if (delegates == null || delegates.Length == 0)
        return defaulDelegate;

    Delegate d = delegates[0] ?? defaulDelegate;
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}
Run Code Online (Sandbox Code Playgroud)

  • 我的第一个问题呢?_为什么返回值使用`?`虽然它已经是引用(类)类型_ (4认同)
  • 因为你要返回 d ,哪个是委托?类型。也可以为 null 或 Delegate,具体取决于参数 (2认同)
  • @snr 返回值使用“?”的原因与参数值使用“?”的原因完全相同。如果你理解了后者,你就自然而然地理解了前者。因为方法*可能返回null*,就像参数*可能接受null*一样。也就是说,它们都*可能包含 null*。 (2认同)
  • 我摸了摸它。我只是用例子回答了第二部分。`既然每个参数都是 Delegate 类型?然后你返回委托的索引?[]?数组,那么返回类型是 Delegate 有意义吗?` (2认同)
  • @snr:_为什么返回值使用 ?尽管它已经是引用(类)类型_(1)如果在类似的代码中也使用了结构,则可能是一种习惯或重构残余(2)在C#8中,不允许引用类型本质上为空(因此需要显式为空( 3) `Foo?` 有一个简洁的 `HasValue` 属性,而 `Foo` 需要检查 `== null` (4) 它向读取方法签名的开发人员传达 null 是可能的、可以预期的,并且(5) 该代码看起来是由非常喜欢可空性并且对此明确的人编写的。 (2认同)

Hol*_*ger 26

可空引用类型是 C# 8.0 中的新增内容,以前不存在。

这是一个文档问题,以及编译时警告是如何产生的。

异常“对象未设置为对象的实例”异常很常见。但这是一个运行时异常,它可以在编译时部分发现。

对于调节器,Delegate d您可以随时致电

 d.Invoke();
Run Code Online (Sandbox Code Playgroud)

意思是,你可以编码它,在编译时什么都不会发生。它可能会在运行时引发异常。

而对于新的Delegate? p此代码

 p.Invoke();
Run Code Online (Sandbox Code Playgroud)

将产生编译器警告。CS8602: Dereference of a possibly null reference 除非你写:

 p?.Invoke();
Run Code Online (Sandbox Code Playgroud)

什么意思,只在不为空时调用。

因此,您记录的变量可能包含空值或不包含空值。它会更早地发出警告,并且可以避免对 null 进行多次测试。你对 int 和 int 有什么相同的?。您肯定知道,一个不为空 - 并且您知道如何将一个转换为另一个。

  • 上次我检查过 NRT 并非 100% 防弹。编译器无法检测到某些边缘情况。 (4认同)

ama*_*kkg 5

在 C# 8 中,应该明确地将引用类型标记为可空。

默认情况下,这些类型不能包含 null,有点类似于值类型。虽然这不会改变引擎盖下的工作方式,但类型检查器将要求您手动执行此操作。

给定的代码经过重构以使用 C# 8,但它并没有从这个新功能中受益。

public static Delegate? Combine(params Delegate?[]? delegates)
{
    // ...[]? delegates - is not null-safe, so check for null and emptiness
    if (delegates == null || delegates.Length == 0)
        return null;

    // Delegate? d - is not null-safe too
    Delegate? d = delegates[0];
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}
Run Code Online (Sandbox Code Playgroud)

这是利用此功能的更新代码示例(不起作用,只是一个想法)。它使我们免于空检查并稍微简化了此方法。

public static Delegate? Combine(params Delegate[] delegates)
{
    // `...[] delegates` - is null-safe, so just check if array is empty
    if (delegates.Length == 0) return null;

    // `d` - is null-safe too, since we know for sure `delegates` is both not null and not empty
    Delegate d = delegates[0];

    for (int i = 1; i < delegates.Length; i++)
        // then here is a problem if `Combine` returns nullable
        // probably, we can add some null-checks here OR mark `d` as nullable
        d = Combine(d, delegates[i]);

    return d;
}
Run Code Online (Sandbox Code Playgroud)

  • `这些类型不能包含 null`,请注意,它会生成编译器**警告**,而不是错误。该代码将正常运行(尽管它可能会生成 NullReferenceExceptions)。这样做是考虑到向后兼容性。 (2认同)