ฉันสามารถบอกอ้างอิง C # nullable ว่าวิธีการตรวจสอบเป็นโมฆะได้อย่างมีประสิทธิภาพในเขตข้อมูล


14

พิจารณารหัสต่อไปนี้:

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

ในการชื่อ = ชื่อ. ToUpper () ฉันได้รับคำเตือนว่าชื่อเป็นการอ้างอิงโมฆะที่เป็นไปได้ซึ่งไม่ถูกต้องชัดเจน ฉันสามารถแก้ไขคำเตือนนี้ได้โดยการใช้ HasName ดังนั้นเงื่อนไขก็คือ (Name! = null)

มีวิธีใดบ้างที่ฉันสามารถสั่งให้คอมไพเลอร์ได้ว่าการตอบสนองที่แท้จริงจาก HasName แสดงถึงข้อ จำกัด ที่ไม่สามารถลบล้างได้ในชื่อ?

นี่เป็นสิ่งสำคัญเนื่องจาก HasName อาจทดสอบสิ่งต่าง ๆ มากมายและฉันอาจต้องการใช้ในหลาย ๆ ที่หรืออาจเป็นส่วนสาธารณะของพื้นผิว API มีหลายเหตุผลที่ต้องการให้แฟคเตอร์ตรวจสอบโมฆะเป็นวิธีของตัวเอง แต่การทำเช่นนั้นดูเหมือนว่าจะทำลายตัวตรวจสอบการอ้างอิงที่เป็นโมฆะ


1
IMO คุณควรใช้HasValueกับประเภทที่ไม่สามารถใช้งานnullได้ อาจไม่ส่งผลกระทบต่อปัญหาของคุณ
fredrik

ผมคิดว่าสำหรับคุณในกรณีนี้คุณสามารถห่อรหัสด้วย#nullable disableแล้ว#nullable enableหรือrestoreอีกครั้งหลังจากนั้น ( docs.microsoft.com/en-us/dotnet/csharp/... )
GaryNg

5
คุณสามารถใช้!โอเปอเรเตอร์"dammit" if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo ไป

1
สำหรับแอปพลิเคชันแบบมัลติเธรดคุณอาจมีชื่อเป็นโมฆะหลังจากการตรวจสอบ HasName โดยใช้ตัวแปรภายในเครื่องแทนที่จะกลับไปที่คุณสมบัติ (ผู้รู้ว่าคุณสมบัติใดที่อาจทำในทะเยอทะยาน) จะให้บั๊กแบบขี้ขลาดบางอย่าง (จำได้ การใช้ตัวจัดการเหตุการณ์ที่เหตุการณ์นี้เกิดขึ้นมากมาย)
XIU

คำตอบ:


3

ฉันมองไปรอบ ๆ คุณลักษณะที่แตกต่างจากSystem.Diagnostics.CodeAnalysisและฉันไม่สามารถหาสิ่งที่ใช้งานได้ซึ่งน่าผิดหวังมาก สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับคือสิ่งที่คุณต้องการ:

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

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

ฉันรู้ว่ามันดูค่อนข้างยุ่งยาก คุณสามารถดูเอกสาร MSDN สำหรับแอตทริบิวต์ที่เป็นค่าว่างได้บางทีคุณอาจพบบางสิ่งที่น่าสนใจ


2
ดูเหมือนว่าเราต้องคุณลักษณะอื่น ๆ หรือสิ่งที่ต้องการยืนยัน typescript ของ
Stilgar

ฉันจะเลือกคำตอบนี้เพราะปรากฏว่าคำตอบที่แท้จริงที่ฉันกลัวคือ "ไม่ c # ยังไม่ได้ทำ"
John Melville

@JohnMelville ฉันไม่สามารถหาข้อเสนอสำหรับคุณลักษณะดังกล่าวได้ดังนั้นฉันไม่คิดว่าเราจะคาดหวังว่าการเปลี่ยนแปลงนี้จะเกิดขึ้นเร็ว ๆ นี้
V0ldek

2
@XIU คอมไพเลอร์หละหลวมในด้านนี้แล้ว หากคุณทำเช่นif(Name != null) return Null.ToUpper()นั้นจะไม่มีการเตือนสำหรับการถูกอ้างถึงเป็นโมฆะแม้ว่าในทางเทคนิคแล้วมันจะเป็นเงื่อนไขการแข่งขันของ TOCTOU ฉันจำ Mads Torgersen พูดเกี่ยวกับวิธีที่พวกเขาพิจารณา แต่มันจะสร้างผลบวกปลอมจำนวนมากคุณสมบัติการอ้างอิงแบบ nullable ทั้งหมดจะไร้ประโยชน์อย่างมีประสิทธิภาพ - 99% ของเวลาที่คุณสมบัติของคุณจะไม่ถูกเปลี่ยนโดยเธรดอื่น ดังนั้นสิ่งที่คุณต้องทำก็คือสร้างแอททริบิวต์ที่จะทำให้การตรวจสอบคุณสมบัตินี้เป็นเสมือนการตรวจสอบค่าว่างของคุณสมบัติอื่น
V0ldek

2
ฉันแก้ไขปัญหา "ไม่สามารถหาข้อเสนอสำหรับเรื่องนี้" ได้ ( github.com/dotnet/csharplang/issues/2997 ) ขอให้ฉันโชคดี
John Melville

-10

สตริงเป็นประเภทอ้างอิงและ nullable (เช่นint?) เป็นประเภทค่า nullable ดังนั้นคุณจึงไม่สามารถจริงๆทำเช่นนี้string? myString; สิ่งที่คุณต้องการคือ:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.