ไกลแค่ไหนที่ 'var' และตัวดำเนินการรวมตัวกันเป็นโมฆะ '??' ได้รับความบันเทิงโดยไม่ขัดขวางการอ่านหรือไม่


23

ฉันรู้ว่าชื่อของคำถามนั้นเป็นอัตนัยมาก แต่ฉันก็ต้องเผชิญกับการใช้งาน??โอเปอร์เรเตอร์โดยเพื่อนร่วมงานของฉันซึ่งในเวลาเดียวกันฉันก็ไม่ค่อยมีความสุข / สบายใจที่ได้ใช้varโค้ดใหม่ที่กำลังมาถึง

อาร์กิวเมนต์ที่ให้สำหรับการใช้??โอเปอเรเตอร์คือมันสามารถอ่านค่าได้ในโค้ด

คำถามของฉันคือสิ่งที่เกิดขึ้นไม่เหมือนกันเมื่อคุณเริ่มใช้var?


49
หาก"นักพัฒนา"ไม่สามารถเข้าใจ??ตัวดำเนินการรวมศูนย์ได้หลังจากอธิบายแล้วพวกเขาไม่ควรได้รับอนุญาตใกล้รหัสการผลิต
CaffGeek

12
ฉันขอแนะนำให้เราเปลี่ยนผู้ดำเนินการจาก ?? เพื่อ IfNull แล้ว ? สามารถ IfSoChoose,: Is ElseChoose + คือเพิ่ม - ลบออกนอกเสียจากว่ามันจะไม่เป็นเอกเทศ - ถูกแยกระหว่าง DecrementBeforeUsing และ DecrementAfterUsing ใน C ++ คุณสามารถทำได้ด้วยมาโคร
Lee Louviere

7
@Xaade: นั่นประชดใช่มั้ย ... ใช่มั้ย ... พระเจ้าปล่อยให้มันน่าขัน (และฉันก็ไม่เชื่อเรื่องพระเจ้า)
Steven Jeuris

10
@StevenJeuris มันอาจจะถากถางแต่ก็ไม่ได้ประชด
Kirk Broadhurst

1
@ KirkBroadhurst: ฉันยืนแก้ไขถูกต้องสับสนทั้งสอง
Steven Jeuris

คำตอบ:


53

ตัวดำเนินการรวมศูนย์ Null (??)

โดยส่วนตัวฉันไม่เห็นข้อเสียในการใช้โอเปอเรเตอร์นี้ พิจารณาตัวอย่างรหัสสามตัวอย่างต่อไปนี้จากตัวดำเนินการใหม่ 'ง่าย' ถึง 'ซับซ้อน'

ไม่มีเวทมนตร์:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

ผู้ประกอบการที่สาม:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

รวมกันเป็นศูนย์:

string name = null;
Console.WriteLine( name ?? "No name set." );

เหตุผลประกอบการเหล่านี้ถูกคิดค้นขึ้นเป็นเพราะพวกเขาเป็นตัวแทนของการดำเนินงานการเขียนโปรแกรมที่พบบ่อยมาก ไม่ต้องการที่จะใช้พวกเขาเพราะคุณไม่ได้ใช้พวกเขาเป็นเพียงการปากแข็ง ภาษาวิวัฒนาการพัฒนาคุณสมบัติเรียนรู้ที่จะใช้พวกเขา!

คำหลัก var

ฉันมีความเห็นแตกต่างกันเล็กน้อยเกี่ยวกับคำหลัก var ประเภทของตัวแปรมักจะให้ข้อมูลเพิ่มเติมเกี่ยวกับรหัสของคุณ ฉันพบว่าการซ่อนประเภทโดยใช้คำหลัก var บางครั้งทำให้โค้ดอ่านน้อยลง คุณรู้น้อยกว่าสิ่งที่คาดหวังโดยไม่ต้องใช้การเติมให้อัตโนมัติหรือโฮเวอร์เหนือตัวบ่งชี้เพื่อดูว่ามันคืออะไร ในความคิดของฉันผลลัพธ์นี้ในรหัสซึ่งช้ากว่าการอ่าน / เขียน

ฉันใช้คำหลักเมื่อพบว่าประเภทไม่ให้ข้อมูลเพิ่มเติมมากนัก

  • ส่วนใหญ่อยู่ในลูป foreachซึ่งฉันได้เรียนรู้จาก Resharper เนื่องจากเป็นฉากที่มี ส่วนใหญ่แล้วคุณจะรู้ว่าคอลเล็กชันประเภทใดที่คุณกำลังทำการสำรวจดังนั้นคุณรู้ว่าคุณคาดหวังไอเท็มจากภายในคอลเล็กชันนั้น
  • คำสั่ง Linq ผลลัพธ์ของการสืบค้น linq มักจะเป็นประเภทสามัญที่ซับซ้อนมาก การแสดงประเภทนี้จะเป็นอันตรายมากกว่าดี
  • ชื่อเกมแบบยาวที่เริ่มต้นได้อย่างง่ายดายด้วยตัวสร้าง คุณสามารถบอกได้ว่าประเภทคืออะไรโดยดูที่ตัวสร้าง

เป็นตัวอย่างสำหรับคำสั่งสุดท้าย:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
ตัวอย่างสุดท้ายนั้นตรงเมื่อคำหลัก var สามารถ excel ลองจินตนาการว่าโค้ดนั้นถูกทิ้งให้เกลื่อนกลาดไปทั่วโค้ดของคุณ ผลตอบแทนFactory.CreateSomeType วันหนึ่งด้วยเหตุผลใดมีการเปลี่ยนแปลงที่จะกลับมาIEnumerable<SomeType> SomeType[]หากคุณใช้ var มันเป็นเพียงการคอมไพล์ใหม่
pdr

1
มีตัวอย่างที่ผิดทางแล้วไปหาอาหาร Numpty! ตัวอย่างที่ดีกว่าคือการใช้ของคุณ เกิดอะไรขึ้นถ้าFactory.CreateSomeType()การเปลี่ยนแปลงกลับISomeType?
pdr

4
@pdr: นั่นน่าจะหมายถึงอินเทอร์เฟซที่เปลี่ยนไปเช่นกันและพฤติกรรมจะต้องมีการปรับ / เพิ่มเช่นกัน หากเป็นเรื่องง่ายที่คุณจะเปลี่ยนชื่อคุณมีการเปลี่ยนชื่ออัตโนมัติ หากการเปลี่ยนแปลง 'สัญญา' ฉันต้องการเห็นรหัสของฉันแตกหักฉันจึงสามารถดูได้ว่าต้องปรับอะไรหรือไม่
Steven Jeuris

2
ฉันคิดว่ามันเป็นไปได้มากว่าหากการคืนค่าชนิดคอนกรีตจะกลับมาเป็นอินเทอร์เฟซที่มันเป็นเพียงการอนุญาตให้คอนกรีตประเภทอื่นที่มีอินเตอร์เฟซเดียวกัน (สอดคล้องกับรูปแบบโรงงาน) แต่ถ้าสัญญามีการเปลี่ยนแปลงรหัสของคุณจะผิดพลาด - แม้ว่าคุณจะพบว่ามันจะหยุดพักในบางกรณีที่มันสำคัญมากกว่าที่ใดก็ได้
pdr

1
@Tom Hawtin เราทุกคนรู้ว่ามันหลีกเลี่ยงไม่ได้nullทั้งหมด นอกจากนี้ยิ่งฉันมองหาทางเลือกnullยิ่งฉันตระหนักถึงการใช้มากขึ้นnullบางครั้งก็เป็นทางออกที่สะอาดที่สุด ตัวอย่างที่ฉันได้รับไม่ใช่สิ่งที่เลวร้ายอย่าง IMHO และฉันพบว่ามันเป็นการใช้งานที่เหมาะสมเป็นประเภทที่ไม่มีค่า
Steven Jeuris

16

var ช่วยให้โค้ด verbose น้อยลงซึ่งเพิ่มความสามารถในการอ่าน ในความคิดของฉันความสามารถในการอ่านไม่ควรวัดจากจำนวนรายละเอียดที่คุณเห็น แต่จะมีการซ่อนรายละเอียดจำนวนเท่าใดในแวบแรก นอกเหนือจากตัวอย่าง Linq แล้ว var ช่วยให้การพิมพ์เป็ดที่ระดับซอร์สโค้ดได้รับตัวอย่างต่อไปนี้:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

ใครจะสนใจประเภทของฉลากตราบใดที่มันมีคุณสมบัติของข้อความ


มีคนพยายามเข้าใจว่าเป็นเช่นฉลาก winforms หรือฉลาก WPF
Steven Jeuris

14
@Steven Jeuris: โดยปกติจะเป็นข้อมูลบริบทที่เป็นที่รู้จัก หากไม่ใช่คุณกำลังเข้าใกล้โค้ดในทางที่ผิด
Codism

ผู้ที่ต้องการทราบว่าเป็นป้ายกำกับเริ่มต้นของ WPF หรือป้ายกำกับที่กำหนดเอง :)
Steven Jeuris

14
1. บุคคลนั้นควรสนใจจริงๆตราบใดที่เป็นป้ายกำกับที่มีคุณสมบัติข้อความ 2. หากนี่เป็นหนึ่งในกรณีที่หายากที่พวกเขาทำจริงๆมีเหตุผลที่ดีในการดูแลถาม Intellisense 3. หากพวกเขากำลังแก้ไขโค้ดใน IDE ที่ไม่มี Intellisense พวกเขาอาจมีวิธีที่ไม่สะดวกกว่า 'var' :)
KutuluMike

4
บางคนมีความรู้สึกที่เป็นนามธรรม
Jim Balter

16

ฉันไม่ได้แสดงความคิดเห็นอย่างจริงจังกับ??ผู้ดำเนินการเนื่องจากฉันไม่เคยใช้ภาษากับผู้ดำเนินการดังกล่าวอย่างหนัก เกี่ยวกับvarโปรแกรมคนในภาษาเช่น Ruby, Python, Perl และ PHP ที่มีการพิมพ์โดยนัยตลอดเวลา ชาวพื้นเมืองของภาษาเหล่านี้ตระหนักดีว่าตัวแปรชนิดที่เป็นทางการมักจะเป็นเสียงที่ไม่เกี่ยวข้อง คุณสนใจสิ่งที่ตัวแปรสามารถทำได้เช่นอินเทอร์เฟซแบบโครงสร้าง / แบบเป็ด

ในทำนองเดียวกันผมเขียนโปรแกรมส่วนใหญ่ใน D. D พิมพ์แบบคงที่ แต่มีคำหลักซึ่งเทียบเท่ากับauto varมันถือว่าเป็นสำนวนที่จะใช้มันได้ทุกที่เว้นแต่คุณจะเห็นความต้องการเฉพาะในการเน้นประเภทของบางสิ่งเพื่อผู้อ่านหรือ (ผ่านการแปลงโดยปริยาย) คอมไพเลอร์ ยกเว้นบางครั้งเมื่อใช้เป็นชนิดส่งคืนฟังก์ชัน (อนุญาตให้ใช้ในรูปแบบ D) ฉันไม่เคยพบว่ามันขัดขวางการอ่านข้อมูลได้เนื่องจากฉันคิดว่าส่วนใหญ่เป็นแง่ของโครงสร้าง / ส่วนต่อประสานเป็ด

นอกจากนี้ IMHO ที่ใช้varทุกที่ที่เป็นไปได้นั้นเป็นตัวอย่างที่ดีของ DRY ประเภทของสิ่งที่ควรระบุในที่เดียวและจากนั้นจะถูกเผยแพร่โดยอัตโนมัติเมื่อใดก็ตามที่จะต้องมีการเผยแพร่ หากคุณใช้varและชนิดที่เป็นทางการของตัวแปรจำเป็นต้องเปลี่ยนแปลงในบางจุดการเปลี่ยนแปลงที่จำเป็นจะถูกเผยแพร่โดยอัตโนมัติทุกที่ที่จำเป็นโดยคอมไพเลอร์ตราบใดที่โปรแกรมยังคงพิมพ์ถูกต้องแทนที่จะเป็นโปรแกรมเมอร์ที่ต้องเปลี่ยนทุกอินสแตนซ์ด้วยตนเอง . นี่คือสิ่งที่ดี (TM)


13

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

อย่างไรก็ตามถ้าทำงานคนเดียวฉันก็จะหา ?? และ var สามารถอ่านได้โดยไม่มีขีด จำกัด แม้

var a = b ?? c ?? d ?? e ?? "";

ค่อนข้างชัดเจนสำหรับฉัน

ผู้ประกอบการที่สามและdynamicเป็นเรื่องที่แตกต่างแน่นอน


4
ฉันจะใช้ `String.Empty 'ที่นี่
งาน

1
@Job, ในความซื่อสัตย์สุจริตเพื่อจะ I. ผมจะใส่อะไรในสตริงที่แล้วไม่ได้คิดอะไร :)
สาธารณรัฐประชาธิปไตยประชาชนลาว

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere

2
@Xaade คุณจะไม่มีวันลืมได้อย่างแน่นอน แต่จริงๆแล้วการใช้ String.Empty หรือ "" เป็นการตั้งค่าส่วนตัว ผมใช้ "" เพราะมันสั้น ...
Carra

12
@Xaade - ถ้าString.Emptyกลับnullมาเราจะอยู่ในนรกที่มีโค้ดที่เสียหายจำนวนมาก
Jesse C. Slicer

10

อาร์กิวเมนต์ที่ให้สำหรับการใช้ ?? โอเปอเรเตอร์คือมันนำไปอ่านในรหัส

คิดสั้น ๆ เกี่ยวกับมันความคิดเห็นนี้บอกฉันว่าคนที่สร้างความคิดเห็นไม่เข้าใจมันเท่าที่ควร เป็นไปได้มากที่สุดในบางสถานการณ์ แต่โดยรวมแล้วฉันไม่ได้ลดอะไรบางอย่างที่ทีม C # คิดว่ามีความสำคัญพอที่จะเพิ่มเพราะ "การอ่าน" ฉันใส่นี้ในหมวดหมู่เดียวกันของ VSif(boolean_object) if(boolean_object == true)บางคนยืนยันว่าข้อที่สองอ่านได้มากขึ้น แต่ในความเป็นจริงมันแค่เพิ่มรหัสพิเศษสำหรับคนที่จะอ่าน / พิมพ์และในบางสถานการณ์อาจทำให้สับสนมากขึ้น (คิดif(boolean_object != false))

คำถามของฉันคือสิ่งเดียวกันไม่เกิดขึ้นเมื่อคุณเริ่มใช้ var ใช่หรือไม่

ทีม C # อนุญาตให้คุณไม่กำหนดสิ่งที่คุณรู้ว่ามันจะเป็นอะไร จนกว่าฉันอย่างต้องกำหนดสิ่งที่ตัวแปรเป็นไปได้ (อย่างใดอย่างหนึ่งมันเป็นสิ่งสำคัญอย่างยิ่งที่วัตถุกลับมาเป็นประเภท x หรือมันคือเรื่องจริงไม่สามารถอ่านได้) varผมใช้ var x = "MY_STRING";ฉันรู้ว่ามันเป็นสตริงจากการมองมัน อันที่จริงฉันไม่สนใจเลยว่ามันจะเป็นสายตราบใดที่มันเป็นสิ่งที่ฉันต้องการให้ทำ การกำหนดประเภทของตัวแปรนั้นเพื่อประโยชน์ของฉันไม่ใช่ของคอมไพเลอร์ หากมีอะไรผิดพลาดคอมไพเลอร์จะบอกฉันเมื่อมันทำงานถ้าฉันมีประเภทตัวแปรที่ไม่ถูกต้อง


0

varคำหลักคือในความคิดของฉันเอาชนะใช้ในสถานการณ์ที่มันถูกนำเดิม - คำสั่ง LINQ ในการค้นหาเหล่านี้ชนิดของผลลัพธ์ที่ส่งคืนมักจะมีชื่อที่ซับซ้อนขนาดใหญ่ซึ่งยากต่อการพิจารณาล่วงหน้าและไม่ช่วยให้ผู้อ่านเข้าใจว่าโค้ดของคุณทำอะไร

อย่างไรก็ตามการทำvar text = "Some text " + variableName + "some more text."มันช่างขี้เกียจ

แก้ไข: @ Jorg คุณได้เพิ่มคำตอบแบบง่ายๆ แต่ไม่ได้เพิ่มการสนทนาใด ๆ ตกลงวิธีนี้เป็นตัวอย่างที่ดีกว่า: var items = doc.DocumentElement.FirstChild.ChildNodes;หากคุณสามารถหาประเภทจากที่ฉันจะให้คุกกี้


18
หากคุณไม่สามารถเข้าใจได้ว่า"Some text "เป็น a stringแล้วคุณมีปัญหาที่ใหญ่กว่าที่จะกังวลมากกว่าจำนวนvars ในโค้ดของคุณ
Jörg W Mittag

3
ปัญหาไม่ได้var; ปัญหาคือชื่อตัวแปร "ไอเท็ม" เส็งเคร็ง varถ้าคุณใช้ชื่อตัวแปรที่ดีมีอะไรผิดปกติกับ
Kyralessa

3
ฉันคาดเดา (โดยไม่มอง) ว่ารายการคือชุดของโหนด XML ซึ่งฉันคาดว่าจะมีคุณสมบัติและวิธีการทั้งหมดของชุดของโหนด XML และนั่นคือทั้งหมดที่ฉันต้องรู้
KutuluMike

หากคุณจำเป็นต้องรู้ว่า var ประเภทใดและไม่สามารถบอกได้ทันทีโดยมองหาเพียงแค่วางเม้าส์ไว้เหนือมัน ไม่ต้องคิดมากที่จะทำ
scrwtp

1
"ขี้เกียจ" - นี่ไม่ใช่ข้อโต้แย้ง ความจริงมันไม่ได้ฉลาดเลย
Jim Balter

0

ฉันมีปัญหาพื้นฐานในการใช้ var

ในตัวอย่างนี้ทุกอย่างเป็นแบบเคียงข้างกัน แต่ปัญหานี้จริง ๆ แล้วมีโซลูชันขนาดใหญ่ที่มีไลบรารีหรือโครงการที่ใช้ร่วมกัน

พิจารณาสิ่งนี้:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

จะเกิดอะไรขึ้นถ้าคนอื่น ๆ GetMeAnObject เปลี่ยนเพื่อให้เหมาะกับความต้องการของพวกเขา?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

เมธอด MainProgram จะมีข้อผิดพลาดสีแดงขนาดใหญ่บน. PerformOperation () เกิดอะไรขึ้น? PerformOperation ทำงานได้ดีอย่างสมบูรณ์มาก่อน เราดูวิธีการใน Object และมันก็หายไปโดยไร้ร่องรอย มันอยู่ที่นั่นเป็นครั้งที่แล้วและเราต้องการวิธีการนั้น คุณสามารถใช้เวลานานในการไล่ล่าหางของคุณและพยายามหาสาเหตุว่าทำไมหาก MyFirstObject มีวิธีที่เรียกว่า PerformOperation ตอนนี้ไม่สามารถมองเห็นได้ ทุกคน "รู้" ว่า GetMeAnObject ส่งคืน MyFirstObject ดังนั้นจึงไม่มีประเด็นที่จะตรวจสอบ

หากคุณพิมพ์ theObject อย่างชัดเจนคุณจะมีข้อผิดพลาด Cast ไม่ถูกต้องบนบรรทัดที่เรียกใช้ GetMeAnObject และจะเห็นได้อย่างชัดเจนว่า GetMeAnObject ส่งคืนชนิดที่ไม่ใช่สิ่งที่คุณคาดหวัง

ในระยะสั้นการประกาศอย่างชัดเจนหมายความว่าคุณรู้ว่าข้อผิดพลาดหมายถึงอะไร การส่งที่ไม่ถูกต้องหมายความว่าคุณคาดว่าจะมีหนึ่งประเภทและส่งคืนประเภทอื่น สมาชิกที่ไม่รู้จักหมายความว่าสมาชิกไม่ได้รับการยอมรับ


10
เพื่อนร่วมงานทำการเปลี่ยนแปลงที่ไม่สมบูรณ์ในโค้ดที่ไม่ครอบคลุมโดยการทดสอบและคุณคิดว่าปัญหาคือvarอะไร ไม่สามารถคาดหวังภาษาที่จะป้องกันพฤติกรรมประเภทนั้น - จะเกิดอะไรขึ้นถ้าพวกเขาต้องการแก้ไข MyFirstObject โดยตรง มันจะยังพังอยู่ แต่ไม่มีไวยากรณ์ใดสามารถช่วยคุณได้ ฉันคิดว่านี่เป็นจุดแข็งvarถึงแม้ว่าจะเกิดอะไรขึ้นถ้าแทนที่จะกลับ MySecondObject ตอนนี้คุณกลับมาที่ IMyFirstObject แทนล่ะ
Phoshi

2
"ทุกคน" รู้ "ว่า GetMeAnObject ส่งคืน MyFirstObject ดังนั้นจึงไม่มีประเด็นที่จะตรวจสอบ" ฉันไม่สามารถนึกถึงสถานการณ์จำลองในการเขียนโปรแกรมที่ฉันต้องพึ่งพาหน่วยความจำของฉันในสิ่งที่ GetMeAnObject ถ้าฉันกำลังดีบัก ถ้าฉันตรวจสอบว่า PerformOperation ไม่ได้อยู่ที่นั่นฉันก็จะเห็นรหัสและไม่มีสำหรับคลาสอื่น ถ้าใน IDE คลาสจะปรากฏขึ้นอินสแตนซ์ที่ฉันดูชนิดของวัตถุ ที่จริงแล้วเมื่อคอมไพเลอร์บอกฉันว่าข้อผิดพลาดมันจะบอกว่า 'คลาส MySecondObject ไม่มีการดำเนินการ PerformOperation' สำหรับทุกคนรู้ได้ยังไง
มูฮัมหมัดอัลคาริ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.