Tôi có thể nói với C # nullable tham khảo rằng một phương thức thực sự là kiểm tra null trên một trường


14

Hãy xem xét các mã sau đây:

#nullable enable
class Foo
{
    public string? Name { get; set; }
    public bool HasName => Name != null;
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

Trên Name = Name.ToUpper () tôi nhận được một cảnh báo rằng Tên là một tham chiếu null có thể, rõ ràng là không chính xác. Tôi có thể chữa cảnh báo này bằng cách nội tuyến HasName để điều kiện là if (Name! = Null).

Có cách nào tôi có thể chỉ dẫn cho trình biên dịch rằng một phản hồi thực sự từ HasName ngụ ý ràng buộc không vô hiệu đối với Tên không?

Điều này rất quan trọng vì HasName thực sự có thể kiểm tra nhiều thứ hơn nữa và tôi có thể muốn sử dụng nó ở một số nơi hoặc nó có thể là một phần công khai của bề mặt API. Có nhiều lý do để muốn đưa yếu tố kiểm tra null vào phương thức riêng của nó, nhưng làm như vậy dường như phá vỡ trình kiểm tra tham chiếu nullable.


1
IMO bạn nên sử dụng HasValuetrên một loại nullable, không kiểm tra nó null. Nó có thể không ảnh hưởng đến vấn đề của bạn mặc dù.
fredrik

Tôi nghĩ đối với trường hợp của bạn, bạn có thể bọc mã của mình #nullable disablesau đó #nullable enablehoặc restoremột lần nữa sau đó ( docs.microsoft.com/en-us/dotnet/csharp/ Lỗi ).
GaryNg

5
bạn có thể sử dụng !toán tử "chết tiệt" . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Đi

1
đối với ứng dụng đa luồng, bạn có thể có Tên là null sau khi kiểm tra HasName, sử dụng biến cục bộ thay vì quay lại thuộc tính (ai biết tài sản có thể làm gì trong getter của nó) sẽ gây ra một số lỗi thú vị (hãy nhớ việc sử dụng một trình xử lý sự kiện trong đó điều này đã xảy ra rất nhiều)
XIU

Câu trả lời:


3

Tôi nhìn xung quanh các thuộc tính khác nhau System.Diagnostics.CodeAnalysisvà tôi không thể tìm thấy bất cứ điều gì có thể áp dụng, điều này rất đáng thất vọng. Gần nhất bạn có thể nhận được những gì bạn muốn dường như là:

public bool TryGetName([NotNullWhen(true)] out string? name)
{
    name = Name;
    return name != null;
}

public void NameToUpperCase()
{
    if (TryGetName(out var name))
    {
        Name = name.ToUpper();
    }
}

Nó trông khá cồng kềnh, tôi biết. Bạn có thể nhìn vào các tài liệu MSDN cho các thuộc tính nullable , có thể bạn sẽ tìm thấy thứ gì đó gọn gàng hơn.


2
Có vẻ như chúng ta cần nhiều thuộc tính hơn hoặc một cái gì đó giống như các xác nhận của bản thảo
Stilgar

Tôi sẽ chọn câu hỏi này làm câu trả lời, vì dường như câu trả lời thực sự, như tôi sợ, là "không, c # chưa làm điều đó."
John Melville

@JohnMelville Tôi cũng không thể tìm thấy một đề xuất cho một tính năng như vậy, vì vậy tôi không nghĩ rằng chúng ta có thể mong đợi điều này thay đổi bất cứ lúc nào sớm.
V0ldek

2
@XIU Trình biên dịch đã lỏng lẻo trong khía cạnh này. Nếu bạn làm như vậy if(Name != null) return Null.ToUpper(), sẽ không có cảnh báo nào về sự vô hiệu hóa, mặc dù về mặt kỹ thuật đó là điều kiện cuộc đua TOCTOU. Tôi nhớ Mads Torgersen nói về cách họ xem xét điều đó, nhưng nó sẽ tạo ra rất nhiều thông tin sai lệch, toàn bộ tính năng loại tham chiếu vô hiệu sẽ vô dụng - 99% thời gian tài sản của bạn sẽ không bị thay đổi bởi một luồng khác. Vì vậy, tất cả những gì bạn cần làm là tạo một thuộc tính làm cho kiểm tra đối với thuộc tính này được coi là kiểm tra null trên thuộc tính khác.
V0ldek

2
Tôi đã khắc phục sự cố "không thể tìm thấy đề xuất cho vấn đề này". ( github.com/dotnet/csharplang/issues/2997 ) Chúc tôi may mắn.
John Melville

-10

Chuỗi là một loại tham chiếu và nullable (ví dụ int?) là các loại giá trị nullable. Vì vậy, bạn không thể thực sự làm điều này string? myString; Những gì bạn cần là đây:

class Foo
{
    public string Name { get; set; }
    public bool HasName => !String.IsNullOrEmpty(Name);  ////assume you want empty to be treated same way as null
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

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.