การแสดงเจตนา
- 5 นาที
ในหน่วยก่อนหน้า คุณได้เรียนรู้วิธีที่คอมไพเลอร์ C# สามารถทําการวิเคราะห์แบบคงที่เพื่อช่วยในการป้องกันNullReferenceException คุณยังได้เรียนรู้วิธีการเปิดใช้งานบริบทที่สามารถเป็น Null ได้ ในหน่วยนี้ คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการแสดงเจตนาของคุณอย่างชัดเจนภายในบริบทที่เป็นค่าว่างได้
การประกาศตัวแปร
เมื่อเปิดใช้งานบริบทที่สามารถเป็น Null ได้ คุณจะสามารถมองเห็นวิธีที่คอมไพเลอร์เห็นโค้ดของคุณได้มากขึ้น คุณสามารถดําเนินการตามคําเตือนที่สร้างขึ้นจากบริบทที่เปิดใช้งานได้และในการทําเช่นนั้นคุณกําลังกําหนดจุดประสงค์ของคุณอย่างชัดเจน ตัวอย่างเช่น ลองตรวจสอบ FooBar โค้ดต่อไปและตรวจสอบการประกาศและการกําหนด:
// Define as nullable
FooBar? fooBar = null;
?โปรดทราบว่า เพิ่มไปยังFooBar ซึ่งบอกคอมไพเลอร์ที่คุณตั้งใจ fooBar ไว้อย่างชัดเจนว่าจะเป็นค่าว่างได้ หากคุณไม่ต้องการ fooBar ให้เป็น Null ได้ แต่คุณยังคงต้องการหลีกเลี่ยงคําเตือน ให้พิจารณาสิ่งต่อไปนี้:
// Define as non-nullable, but tell compiler to ignore warning
// Same as FooBar fooBar = default!;
FooBar fooBar = null!;
ตัวอย่างนี้เพิ่มตัวดําเนินการ null-forgiving (!) ไปยัง nullซึ่งแนะนําคอมไพเลอร์ว่าคุณกําลังเริ่มต้นตัวแปรนี้เป็น null อย่างชัดเจน คอมไพเลอร์จะไม่ออกคําเตือนเกี่ยวกับการอ้างอิงนี้เป็น null
แนวทางปฏิบัติที่ดีคือการกําหนดตัวแปรที่ไม่ใช่null ค่าว่างของคุณเมื่อได้รับการประกาศ หากเป็นไปได้:
// Define as non-nullable, assign using 'new' keyword
FooBar fooBar = new(Id: 1, Name: "Foo");
ผู้ ประกอบการ
ดังที่กล่าวไว้ในหน่วยก่อนหน้า C# กําหนดตัวดําเนินการหลายตัวเพื่อแสดงเจตนารอบชนิดการอ้างอิงที่สามารถเป็น Nullable ของคุณได้
ตัวดําเนินการ Null-forgiving (!)
คุณได้รับการแนะนําให้ใช้ตัวดําเนินการให้ null (!) ในส่วนก่อนหน้า ซึ่งแจ้งให้คอมไพเลอร์ละเว้นคําเตือน CS8600 นี่คือวิธีหนึ่งในการบอกคอมไพเลอร์ที่คุณรู้ว่ากําลังทําอะไร แต่มันมาพร้อมกับคําเตือนที่คุณควร รู้ว่าคุณกําลังทําอะไรอยู่!
เมื่อคุณเริ่มต้นประเภทที่ไม่สามารถเป็น null ได้ในขณะที่มีการเปิดใช้งานบริบทที่สามารถเป็น null ได้ คุณอาจจําเป็นต้องขอให้คอมไพเลอร์ทําการให้อภัย ตัวอย่างเช่น พิจารณาโค้ดต่อไปนี้:
#nullable enable
using System.Collections.Generic;
var fooList = new List<FooBar>
{
new(Id: 1, Name: "Foo"),
new(Id: 2, Name: "Bar")
};
FooBar fooBar = fooList.Find(f => f.Name == "Bar");
// The FooBar type definition for example.
record FooBar(int Id, string Name);
ในตัวอย่างFooBar fooBar = fooList.Find(f => f.Name == "Bar");ก่อนหน้า สร้างคําเตือน CS8600 เนื่องจากFindอาจส่งกลับnull ซึ่งnullfooBarไม่สามารถเป็นค่าว่างได้ในบริบทนี้ อย่างไรก็ตามในตัวอย่างที่โน้มนวยนี้เรารู้ว่า Find จะไม่ส่งกลับ null เป็นลายลักษณ์อักษร คุณสามารถแสดงเจตนานี้ไปยังคอมไพเลอร์ด้วยตัวดําเนินการ null-forgiving:
FooBar fooBar = fooList.Find(f => f.Name == "Bar")!;
!สังเกต ที่ส่วนท้ายของfooList.Find(f => f.Name == "Bar") ซึ่งบอกคอมไพเลอร์ว่าคุณทราบว่าออบเจ็กต์ที่ส่งกลับโดย Find เมธอด อาจเป็น nullและไม่เป็นไร
คุณสามารถใช้ตัวดําเนินการ null-forgiving กับวัตถุแบบอินไลน์ก่อนที่จะเรียกเมธอดหรือการประเมินคุณสมบัติได้เช่นกัน พิจารณาตัวอย่างอื่นที่มีข้อจํากัด:
List<FooBar>? fooList = FooListFactory.GetFooList();
// Declare variable and assign it as null.
FooBar fooBar = fooList.Find(f => f.Name == "Bar")!; // generates warning
static class FooListFactory
{
public static List<FooBar>? GetFooList() =>
new List<FooBar>
{
new(Id: 1, Name: "Foo"),
new(Id: 2, Name: "Bar")
};
}
// The FooBar type definition for example.
record FooBar(int Id, string Name);
ในตัวอย่างก่อนหน้า:
-
GetFooListเป็นเมธอดแบบคงที่ที่ส่งกลับชนิดList<FooBar>?nullable -
fooListได้รับการกําหนดค่าที่ส่งกลับโดยGetFooList - คอมไพเลอร์สร้างคําเตือนบน
fooList.Find(f => f.Name == "Bar");เนื่องจากค่าที่กําหนดให้fooListอาจเป็นnull -
fooListสมมติว่าไม่ใช่nullFindอาจส่งกลับnullแต่เราทราบว่าไม่เป็นดังนั้นตัวดําเนินการการให้อภัย null จะถูกนําไปใช้
คุณสามารถใช้ตัวดําเนินการ null-forgiving เพื่อ fooList ปิดใช้งานคําเตือน:
FooBar fooBar = fooList!.Find(f => f.Name == "Bar")!;
หมายเหตุ
คุณควรใช้ตัวดําเนินการการให้ค่า null อย่างเป็นทางการ ใช้มันเพื่อยกเลิกคําเตือนหมายความว่าคุณกําลังบอกคอมไพเลอร์ไม่ให้ช่วยให้คุณค้นพบ null ที่อาจผิดพลาดได้ ใช้การดําเนินการนี้อย่างครอบคลุม และเฉพาะเมื่อคุณแน่ใจเท่านั้น
สําหรับข้อมูลเพิ่มเติม, อ้างอิงที่ ตัวดําเนินการ (null-forgiving) (การอ้างอิง C#)
ตัวดําเนินการ Null-coalescing (??)
เมื่อทํางานกับชนิดที่เป็นค่าว่างได้ คุณอาจจําเป็นต้องประเมินว่าตัวแปรเหล่านั้นกําลังทํางานอยู่ในขณะนี้ null และดําเนินการบางอย่างหรือไม่ ตัวอย่างเช่น เมื่อมีการกําหนด null ชนิดที่สามารถเป็น Null ได้หรือไม่ได้กําหนดค่าเริ่มต้น คุณอาจจําเป็นต้องกําหนดค่าที่ไม่ใช่ null ให้พวกเขา ซึ่งเป็นจุดที่ตัวดําเนินการ null-coalescing (??) มีประโยชน์
พิจารณาตัวอย่างต่อไปนี้:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
salesTax ??= DefaultStateSalesTax.Value;
// Safely use salesTax object.
}
ในโค้ด C# ก่อนหน้า:
- พารามิเตอร์
salesTaxได้รับการกําหนดให้เป็น null ได้IStateSalesTax - ภายในเนื้อความวิธีการ
salesTaxจะมีการกําหนด ตามเงื่อนไขโดยใช้ตัวดําเนินการ null-coalescing- ซึ่งทําให้แน่ใจว่าถ้ามี
salesTaxการส่งผ่านเนื่องจากnullจะมีค่า
- ซึ่งทําให้แน่ใจว่าถ้ามี
เคล็ดลับ
ซึ่งเทียบเท่ากับโค้ด C# ต่อไปนี้:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
if (salesTax is null)
{
salesTax = DefaultStateSalesTax.Value;
}
// Safely use salesTax object.
}
นี่คือตัวอย่างของสํานวน C# ทั่วไปอื่นที่ตัวดําเนินการรวมค่า null จะมีประโยชน์:
public sealed class Wrapper<T> where T : new()
{
private T _source;
// If given a source, wrap it. Otherwise, wrap a new source:
public Wrapper(T source = null) => _source = source ?? new T();
}
โค้ด C# ก่อนหน้า:
- กําหนดคลาส wrapper ทั่วไปที่พารามิเตอร์ชนิดทั่วไปถูกจํากัดอยู่ที่
new() - คอนสตรักเตอร์ยอมรับ
T sourceพารามิเตอร์ที่เป็นค่าเริ่มต้นnull - การครอบ
_sourceจะถูกเตรียมใช้งานตามเงื่อนไขเป็นnew T()
สําหรับข้อมูลเพิ่มเติม เช็คเอาท์ ?? และ ?? = ตัวดําเนินการ (การอ้างอิง C#)
ตัวดําเนินการแบบมีเงื่อนไข Null (?.)
เมื่อทํางานกับชนิด nullable คุณอาจต้องดําเนินการตามเงื่อนไขโดยยึดตามสถานะของ null วัตถุ ตัวอย่างเช่น: ในหน่วยFooBarก่อนหน้า ระเบียน ถูกใช้เพื่อสาธิตNullReferenceExceptionโดย dereferencing null มันเกิดขึ้นตอนที่ถูกเรียกตัว ToString มา พิจารณาตัวอย่างเดียวกันนี้ แต่ตอนนี้ใช้ตัวดําเนินการแบบมีเงื่อนไข null:
using System;
// Declare variable and assign it as null.
FooBar fooBar = null;
// Conditionally dereference variable.
var str = fooBar?.ToString();
Console.Write(str);
// The FooBar type definition.
record FooBar(int Id, string Name);
โค้ด C# ก่อนหน้า:
- การอนุมาน
fooBarตามเงื่อนไข ที่กําหนดผลลัพธ์ของToStringให้กับstrตัวแปร- ตัวแปร
strเป็นชนิดstring?(สตริงที่สามารถเป็น null ได้)
- ตัวแปร
- ซึ่งเขียนค่าของ
strไปยังเอาต์พุตมาตรฐาน ซึ่งไม่มีเลย - การเรียก
Console.Write(null)ถูกต้อง ดังนั้นจึงไม่มีคําเตือน - คุณจะได้รับคําเตือนหากคุณต้องการเรียกใช้
Console.Write(str.Length)เนื่องจากคุณอาจลดค่า null ได้
เคล็ดลับ
ซึ่งเทียบเท่ากับโค้ด C# ต่อไปนี้:
using System;
// Declare variable and assign it as null.
FooBar fooBar = null;
// Conditionally dereference variable.
string str = (fooBar is not null) ? fooBar.ToString() : default;
Console.Write(str);
// The FooBar type definition.
record FooBar(int Id, string Name);
คุณสามารถรวมตัวดําเนินการเพื่อแสดงเจตนาของคุณเพิ่มเติมได้ ตัวอย่างเช่น คุณสามารถเกี่ยวโยงตัว ?. ดําเนินการ และ ?? :
FooBar fooBar = null;
var str = fooBar?.ToString() ?? "unknown";
Console.Write(str); // output: unknown
สําหรับข้อมูลเพิ่มเติม อ้างอิง ? และ ?[] (null-conditional) operators
สรุป
ในหน่วยนี้ คุณได้เรียนรู้เกี่ยวกับการแสดงเจตนา Nullability ของคุณในโค้ด ในหน่วยถัดไป คุณจะนําสิ่งที่คุณได้เรียนรู้ไปใช้กับโครงการที่มีอยู่
ตรวจสอบความรู้ของคุณ
คำติชม
หน้านี้มีประโยชน์หรือไม่
ไม่
ต้องการความช่วยเหลือในหัวข้อนี้หรือไม่
ต้องการลองใช้ Ask Learn เพื่อทําให้ชัดเจนหรือแนะนําคุณผ่านหัวข้อนี้หรือไม่