อะไรคือ ?[]? ไวยากรณ์ใน C #?


85

ขณะที่ผมกำลังศึกษาผู้ร่วมประชุมที่เป็นจริงในระดับนามธรรม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;
}


23
มันเป็นอาร์เรย์ที่ไม่มีค่าที่สามารถมีค่าที่เป็นค่าว่างได้หรือ
Cid

3
c # 8 ตอนนี้คุณสามารถระบุได้ว่าตัวแปรวัตถุไม่ได้รับอนุญาตให้เป็นโมฆะ หากคุณพลิกธงคอมไพเลอร์ที่คุณจะต้องระบุตัวแปรที่ทุกคนจะได้รับอนุญาตให้เป็นโมฆะ
Jeremy Lakeman

คำตอบ:


66

คำอธิบายทีละขั้นตอน:

params Delegate?[] delegates - มันเป็นอาร์เรย์ของ nullable 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
แล้วคำถามแรกของฉันล่ะ เหตุใดค่าส่งคืนจึงถูกใช้?ถึงแม้ว่าจะเป็นประเภทอ้างอิง (คลาส) แล้ว
snr - Reinstate Monica

2
เพราะคุณจะกลับมาซึ่งเป็นผู้ได้รับมอบหมาย? ชนิด และยังเป็นโมฆะหรือมอบหมายขึ้นอยู่กับพารามิเตอร์
Athanasios Kataras

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

2
@snr: เหตุใดค่าส่งคืนจึงใช้ แม้ว่ามันจะเป็นประเภทอ้างอิง (คลาส) (1) มันอาจจะเป็นนิสัยหรือส่วนที่เหลือ refactoring ถ้า structs ยังใช้ในรหัสที่คล้ายกัน (2) ใน C # 8 ประเภทการอ้างอิงสามารถไม่อนุญาตให้เป็นโมฆะโดยเนื้อแท้ 3) Foo?มีHasValueคุณสมบัติที่เป็นระเบียบในขณะที่Fooต้องมี== nullการตรวจสอบ (4) มันสื่อสารกับนักพัฒนาที่อ่านลายเซ็นวิธีที่เป็นโมฆะเป็นไปได้ที่จะคาดหวังและผลลัพธ์ที่ถูกต้อง (5) รหัสดูเหมือนว่าจะเขียนโดยคนที่ ชอบความไร้ค่าและมีความชัดเจนเกี่ยวกับเรื่องนี้
Flater

25

ประเภทการอ้างอิงที่ Nullableเป็นสิ่งใหม่ใน C # 8.0 ซึ่งไม่มีอยู่ก่อนหน้านี้

มันเป็นเรื่องของเอกสารประกอบและการสร้างคำเตือน ณ เวลารวบรวม

ข้อยกเว้น "วัตถุที่ไม่ได้ตั้งค่าเป็นอินสแตนซ์ของวัตถุ" ข้อยกเว้นคือเงียบทั่วไป แต่นี่เป็นข้อยกเว้นรันไทม์สามารถค้นพบบางส่วนในเวลารวบรวมแล้ว

สำหรับการควบคุมDelegate dคุณสามารถโทรหาได้ตลอดเวลา

 d.Invoke();

ความหมายคุณสามารถรหัสได้ในเวลารวบรวมไม่มีอะไรจะเกิดขึ้น มันอาจเพิ่มข้อยกเว้นที่รันไทม์

สำหรับDelegate? pรหัสใหม่นี้

 p.Invoke();

จะสร้างคำเตือนคอมไพเลอร์ CS8602: Dereference of a possibly null reference ถ้าคุณไม่เขียน:

 p?.Invoke();

สิ่งที่หมายถึงโทรเฉพาะในกรณีที่ไม่เป็นโมฆะ

ดังนั้นเอกสารของตัวแปรอาจมีค่าว่างหรือไม่ เตือนก่อนหน้านี้และสามารถหลีกเลี่ยงการทดสอบหลายรายการสำหรับค่า Null สิ่งที่คุณมีเหมือนกันสำหรับ int และ int? คุณรู้แน่ว่าไม่มีใครว่าง - และคุณรู้วิธีแปลงหนึ่งเป็นอีก


กับข้อแม้ที่คุณไม่รู้ว่าDelegateไม่เป็นโมฆะ คุณแกล้งทำเป็นว่าคุณรู้แน่นอน (ซึ่งดีพอในกรณีส่วนใหญ่)
Tim Pohlmann

@TimPohlmann เช่นเดียวกับ int i = null เป็นไปไม่ได้และสตริง s = null นั้นเป็นไปไม่ได้ (ใน C # 8 ที่มีการเปลี่ยนแปลงการแบ่งนี้) ดังนั้นมันจึงเป็นอะไรที่แสร้งทำเป็นมากกว่า สำหรับความเข้ากันได้แบบย้อนหลังมันถูกลดระดับเป็นคำเตือน หากคุณอัพเกรดคำเตือนเป็นข้อผิดพลาดคุณรู้แน่ว่ามันไม่เป็นโมฆะ
Holger

4
ครั้งล่าสุดที่ฉันตรวจสอบ NRT ไม่ใช่กระสุนพิสูจน์ 100% มีบางกรณีที่ผู้รวบรวมไม่สามารถตรวจจับขอบได้
Tim Pohlmann

ใช่ แต่นี่จะเหมือนกับคำว่า "ตัวแปรไม่ได้เริ่มต้น" หรือ "ไม่ใช่เส้นทางรหัสทั้งหมดที่ส่งคืนค่า" คำเตือน นั่นคือคุณสมบัติการคอมไพล์เวลาทั้งหมด 100% โดยไม่มีการตรวจจับในขณะทำงาน ฉันคิดว่าพวกเขาจะไม่เพิ่มหน่วยความจำพิเศษเพื่อเก็บข้อมูลเพิ่มเติม สมมุติว่ามันมีความน่าเชื่อถือเท่ากับระบบ Intellisense ใช้ได้ดีทีเดียว.
Holger

1
หากคุณมีintมันไม่สามารถเป็นโมฆะ หากคุณมีDelegateมันอาจเป็นโมฆะ (ด้วยเหตุผลหลายประการเช่นการสะท้อน) มันจะปลอดภัยที่จะสมมติว่าDelegate(ใน C # 8 ที่เปิดใช้งาน NRT) ไม่เป็นโมฆะ แต่คุณไม่เคยรู้แน่นอน (ที่intเราทราบแน่นอน)
Tim Pohlmann

5

ใน C # 8 หนึ่งควรทำเครื่องหมายประเภทการอ้างอิงเป็น nullable อย่างชัดเจน

โดยค่าเริ่มต้นประเภทเหล่านั้นจะไม่สามารถมีโมฆะชนิดคล้ายกับประเภทค่า แม้ว่าสิ่งนี้จะไม่เปลี่ยนวิธีการทำงานของสิ่งต่าง ๆ ภายใต้ประทุนเครื่องตรวจสอบชนิดจะกำหนดให้คุณทำสิ่งนี้ด้วยตนเอง

รหัสที่ได้รับจะถูก refactored ให้ทำงานร่วมกับ 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;
}

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

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