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


85

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

  • 为什么返回值?已经使用了reference(class)类型,为什么要使用
  • ?[]? 参数含义

你能解释一下吗?

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;
}


23
它不是可以包含可空值的可空数组吗?
Cid

3
c#8,您现在可以指定一个对象变量不允许为null。如果你翻车是编译器标志,你必须指定每一个变量允许为空。
杰里米·莱克曼

Answers:


66

逐步说明:

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;
}

4
那我的第一个问题呢?为什么返回值?虽然已经是引用(类)类型
仍要

2
因为您要返回d是代表?类型。根据参数还可以为null或Delegate
Athanasios Kataras 19/12/29

2
@snr返回值使用的?原因与参数值使用的原因完全相同?。如果您了解后者,那么您将自动了解前者。因为该方法可能返回null,所以该参数可能会接受null。也就是说,它们都可以包含null
GSerg

2
我感动了 我只是作为示例的第二部分回答了它。Since each parameter is of the type Delegate? and you return an index of the Delegate?[]? array, then it makes sense that the return type is Delegate?
Athanasios Kataras 19/12/29

2
@snr:为什么使用返回值?尽管它已经是引用(类)类型(1)如果在相似的代码中也使用了结构,则可能是一种习惯,也可能是重构的残余(2)在C#8中,可以不允许引用类型本质上是可为null的(因此需要显式为null( 3)Foo?具有一个整洁的HasValue属性,而Foo需要== null检查(4)它与读取方法签名的开发人员进行通信,告知他们可能为null,可能是预期的和正确的结果为null(5)该代码看起来是由某人编写的很喜欢空性的并且是明确了。
Flater

25

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

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

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

对于监管,Delegate d您可以随时致电

 d.Invoke();

意思是,您可以进行编码,在编译时不会发生任何事情。它可能会在运行时引发异常。

而对于新的Delegate? p本规范

 p.Invoke();

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

 p?.Invoke();

是什么意思,仅在不为null时调用。

因此,您记录的变量可能包含null或不包含null。它会提早发出警告,并且可以避免针对null的多次测试。和int和int一样。您肯定知道一个都不为空-并且您知道如何将一个转换为另一个。


请注意,您肯定不知道该警告不为Delegatenull。您只是假装您肯定知道(在大多数情况下这已经足够了)。
蒂姆·波曼

@TimPohlmann和int i = null一样是不可能的,字符串s = null也是不可能的(在C#8中有此重大更改)。因此,它不过是假装什么。为了向后兼容,它已降级为警告。如果将警告升级为错误,则可以肯定它不是null。
Holger

4
上次我检查NRT不是100%防弹。在某些情况下,编译器无法检测到。
蒂姆·波曼

是的,但这与“未初始化变量”或“并非所有代码路径都返回值”的警告相同。所有这些都是100%的编译时功能,无需在运行时进行检测。与int?不同,我认为它们不会增加额外的内存来容纳额外的信息。因此,可以说它与智能感知一样可靠。非常好。
Holger

1
如果有,int则永远不能为null。如果有Delegate,则可以为null(出于各种原因,例如反射)。通常可以安全地假设Delegate(在启用了NRT的C#8中)不为null,但是您永远无法确定(int我们肯定知道的地方)。
蒂姆·波曼

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;
}

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

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;
}

2
those types are not able to contain null,请注意它会生成一个编译器警告,而不是错误。该代码可以正常运行(尽管它可能会生成NullReferenceExceptions)。这样做时要考虑向后兼容性。
JAD
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.