Cái gì? []? cú pháp trong C #?


85

Trong khi tôi đang nghiên cứu các đại biểu trong đó thực sự là một lớp trừu tượng trong Delegate.cs, tôi thấy các phương pháp sau đây trong đó tôi không hiểu

  • Tại sao giá trị trả về sử dụng ?mặc dù nó đã là loại tham chiếu ( lớp )
  • ?[]? ý nghĩa của tham số

Bạn có thể giải thích?

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
Nó không phải là một mảng nullable có thể chứa các giá trị nullable?
Cid

3
c # 8, bây giờ bạn có thể chỉ định rằng một biến đối tượng không được phép là null. Nếu bạn lật cờ trình biên dịch đó, bạn phải chỉ định mọi biến được phép là null.
Jeremy Lakeman

Câu trả lời:


66

Từng bước giải thích:

params Delegate?[] delegates - Nó là một mảng của nullable Delegate

params Delegate?[]? delegates - Toàn bộ mảng có thể là nullable

Vì mỗi tham số thuộc loại Delegate?và bạn trả về một chỉ mục của Delegate?[]?mảng, nên có nghĩa là kiểu trả về Delegate?nếu không trình biên dịch sẽ trả về lỗi như thể bạn đang giữ lại và inttừ một phương thức trả về một chuỗi.

Ví dụ, bạn có thể thay đổi mã của mình để trả về một Delegatekiểu như thế này:

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
Còn câu hỏi đầu tiên của tôi thì sao? Tại sao giá trị trả về sử dụng ?mặc dù loại đã tham chiếu (lớp)
snr - Phục hồi Monica

2
Bởi vì bạn đang trở lại d đó là Đại biểu? kiểu. Và cũng null hoặc Đại biểu tùy thuộc vào các tham số
Athanasios Kataras

2
@snr Giá trị trả về sử dụng ?chính xác cho cùng một lý do tại sao giá trị đối số sử dụng ?. Nếu bạn hiểu cái sau, bạn sẽ tự động hiểu cái trước. Bởi vì phương thức có thể trả về null , giống như tham số có thể chấp nhận null . Đó là, cả hai có thể chứa null .
GSerg

2
Tôi chạm vào nó. Tôi chỉ trả lời nó như phần thứ hai với ví dụ. 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

2
@snr: Tại sao giá trị trả về sử dụng? mặc dù nó đã là loại tham chiếu (lớp) (1) Nó có thể là thói quen hoặc phần còn lại tái cấu trúc nếu các cấu trúc cũng được sử dụng trong mã tương tự (2) Trong các loại tham chiếu C # 8 có thể không được phép vốn có thể bị vô hiệu hóa (do đó yêu cầu vô hiệu rõ ràng ( 3) Foo?có một thuộc tính gọn gàng HasValue, trong khi Foocần phải == nullkiểm tra (4) Nó thông báo cho các nhà phát triển đọc chữ ký phương thức rằng null là có thể, được mong đợi và kết quả chính xác. (5) Mã dường như được viết bởi một người nào đó rất thích sự vô hiệu và rõ ràng về nó.
Flater

25

Các loại tham chiếu Nullable là mới trong C # 8.0, chúng không tồn tại trước đây.

Đó là vấn đề về tài liệu và cách cảnh báo tại thời điểm biên dịch được tạo ra.

Ngoại lệ "đối tượng không được đặt thành phiên bản của đối tượng" ngoại lệ là phổ biến yên tĩnh. Nhưng đây là một ngoại lệ thời gian chạy, nó có thể được phát hiện một phần tại thời điểm biên dịch.

Đối với một quy định Delegate dbạn luôn có thể gọi

 d.Invoke();

có nghĩa là, bạn có thể mã nó, tại thời điểm biên dịch sẽ không có gì xảy ra. Nó có thể đưa ra ngoại lệ trong thời gian chạy.

Trong khi đối với một mã mới Delegate? pnày

 p.Invoke();

sẽ tạo ra một cảnh báo trình biên dịch. CS8602: Dereference of a possibly null reference trừ khi bạn viết:

 p?.Invoke();

có nghĩa là gì, chỉ gọi nếu không null.

Vì vậy, bạn tài liệu một biến có thể chứa null hoặc không. Nó đưa ra cảnh báo sớm hơn và nó có thể tránh được nhiều thử nghiệm cho null. Giống như những gì bạn có cho int và int?. Bạn biết chắc chắn, cái này không phải là null - và bạn biết làm thế nào để chuyển đổi cái này sang cái khác.


với lời cảnh báo mà bạn không biết chắc chắn đó Delegatekhông phải là null. Bạn chỉ giả vờ rằng bạn biết chắc chắn (điều đó đủ tốt trong hầu hết các trường hợp).
Tim Pohlmann

@TimPohlmann Cũng như int i = null là không thể, cũng có một chuỗi s = null là không thể (trong C # 8 với thay đổi đột phá này). Vì vậy, nó ít hơn là giả vờ một cái gì đó. Để tương thích ngược, nó bị hạ xuống thành một cảnh báo. Nếu bạn nâng cấp cảnh báo thành lỗi, bạn biết chắc chắn đó không phải là null.
Holger

4
Lần trước tôi đã kiểm tra NRT không phải là bằng chứng đạn 100%. Có một số trường hợp cạnh nhất định trình biên dịch không thể phát hiện.
Tim Pohlmann

Có, nhưng điều này giống như cảnh báo "biến không được khởi tạo" hoặc "không phải tất cả các đường dẫn mã trả về giá trị". Đó là tất cả các tính năng biên dịch 100%, không bị phát hiện khi chạy. Không giống như int?, Tôi nghĩ rằng họ không thêm bộ nhớ để chứa thêm thông tin. Vì vậy, hãy nói rằng nó đáng tin cậy như intellisense. Khá tốt.
Holger

1
Nếu bạn có một intnó không bao giờ có thể là null. Nếu bạn có Delegatenó có thể là null (vì nhiều lý do, ví dụ như sự phản chiếu). Thông thường sẽ an toàn khi cho rằng Delegate(trong C # 8 có bật NRT) không phải là null, nhưng bạn không bao giờ biết chắc chắn (nơi mà intchúng tôi biết chắc chắn).
Tim Pohlmann

5

Trong C # 8, người ta nên đánh dấu rõ ràng các loại tham chiếu là nullable.

Theo mặc định, các loại đó không thể chứa null, tương tự như các loại giá trị. Mặc dù điều này không thay đổi cách mọi thứ hoạt động dưới mui xe, trình kiểm tra loại sẽ yêu cầu bạn thực hiện việc này một cách thủ công.

Mã đã cho được tái cấu trúc để hoạt động với C # 8, nhưng nó không được hưởng lợi từ tính năng mới này.

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

Dưới đây là một ví dụ về mã được cập nhật (không hoạt động, chỉ là một ý tưởng) tận dụng tính năng này. Nó đã cứu chúng tôi khỏi kiểm tra null và đơn giản hóa phương pháp này một chút.

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, lưu ý rằng nó tạo ra một cảnh báo trình biên dịch , không phải là một lỗi. Mã sẽ chạy tốt (mặc dù nó có thể tạo NullReferenceExceptions). Điều này được thực hiện với sự tương thích ngược trong tâm trí.
JAD
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.