โอเปอเรเตอร์ที่มีเงื่อนไขแบบใหม่ของ C # 6.0 นั้นผิดกฎหมายหรือไม่?


29

กฎหมายของ Demeterกล่าวต่อไปนี้:

  • แต่ละหน่วยควรมีความรู้ที่ จำกัด เฉพาะเกี่ยวกับหน่วยอื่น ๆ : เฉพาะหน่วย "อย่างใกล้ชิด" ที่เกี่ยวข้องกับหน่วยปัจจุบัน
  • แต่ละหน่วยควรคุยกับเพื่อนเท่านั้น อย่าคุยกับคนแปลกหน้า
  • พูดคุยกับเพื่อนของคุณทันที

C # 6.0 แนะนำผู้ประกอบการใหม่ที่เรียกว่าผู้ประกอบการ null เงื่อนไข IMHO ทำให้การเข้ารหัสง่ายขึ้นและปรับปรุงความสามารถในการอ่าน แต่มันยังทำให้ง่ายต่อการเขียนรหัสคู่มากขึ้นเนื่องจากง่ายต่อการเลื่อนดูฟิลด์คลาสและตรวจสอบค่าว่าง (เช่นvar x = A?.B?.C?.D?.E?.F?)

ถูกต้องหรือไม่หากระบุว่าผู้ประกอบการรายใหม่นี้ขัดต่อกฎหมายของ Demeter


2
ทำไมคุณเชื่อว่าA?.B?.C?.D?.E?.F?มันจะเป็นการละเมิด - LoD ไม่ได้เกี่ยวกับจำนวนจุดและถ้าวิธีการโทรมีข้อมูลเกี่ยวกับโครงสร้างที่ไม่ได้เป็นการละเมิดจุดนั้นการโทรนั้นจะเป็นที่ยอมรับอย่างสมบูรณ์ รหัสดังกล่าวอาจละเมิด LoD ไม่เพียงพอที่จะกล่าวได้ว่าการใช้งานทั้งหมดจะเป็นการละเมิด LoD

14
การอ่าน " กฎของ Demeter ไม่ใช่การออกกำลังกายนับจุด "? มันกล่าวถึงตัวอย่างที่แน่นอนนี้
outis

@outis: excelent read ฉันไม่ได้บอกว่าทุกรหัสในรูปแบบของX.Y.Z.W.Uเป็นการละเมิด "กฎหมาย" แต่ในประสบการณ์ของฉันเกี่ยวกับรหัส 90% ของเวลามันเป็นเพียงรหัสคู่ที่น่าเกลียดธรรมดา
Arthur Rizzo

2
@ArthurRizzo แต่นั่นไม่ใช่ปัญหากับตัวดำเนินการ null ที่มีเงื่อนไขซึ่งเทียบกับ LoD นั่นคือรหัสที่ผิด ผู้ประกอบการเป็นเพียงเครื่องมือในการลดความซับซ้อนของการอ่านของมนุษย์ .?ไม่มากละเมิด LoD กว่า+หรือ-ไม่

1
RC Martin แยกความแตกต่างระหว่างคลาสข้อมูลบริสุทธิ์และคลาสพฤติกรรม หากคุณสมบัติที่เข้าถึงได้เปิดเผยข้อมูลภายในของคลาสพฤติกรรมตัวอย่างข้อมูลนั้นละเมิด LoD แต่สิ่งนี้ไม่มีส่วนเกี่ยวข้องกับตัวดำเนินการ null ตามเงื่อนไข อย่างไรก็ตามคุณสมบัติไม่ได้ถูกผูกไว้เพื่อเปิดเผยข้อมูลภายในซึ่งอาจเป็นกลิ่น แต่ไม่ได้ละเมิด LoD ตาม RC Martin schema อาจใช้ได้จริงกับคลาส data ที่แท้จริง
Paul Kertscher

คำตอบ:


44

ถูกต้องหรือไม่หากระบุว่าผู้ประกอบการรายใหม่นี้ขัดต่อกฎหมายของ Demeter

ไม่*


*ตัวดำเนินการเงื่อนไขแบบ null เป็นเครื่องมือภายในภาษาและ. NET Framework เครื่องมือใด ๆที่มีความสามารถในการถูกทารุณกรรมและใช้งานในลักษณะที่อาจเป็นอันตรายต่อการบำรุงรักษาของแอปพลิเคชันที่กำหนด

แต่ความจริงที่ว่าเครื่องมือที่สามารถถูกทำร้ายไม่ได้หมายความว่ามันมีการถูกทำร้ายหรือว่าเครื่องมือที่ละเมิดหลักการใด ๆ โดยเฉพาะ (s) ที่อาจจะจัดขึ้น

กฎหมายของ Demeter และอื่น ๆ เป็นแนวทางเกี่ยวกับวิธีที่คุณควรเขียนรหัสของคุณ มันเป็นเป้าหมายของมนุษย์ไม่ใช่เครื่องมือ ดังนั้นความจริงที่ว่าภาษา C # 6.0 มีเครื่องมือใหม่อยู่ภายในนั้นไม่จำเป็นต้องส่งผลกระทบต่อวิธีการเขียนและจัดโครงสร้างโค้ดของคุณ

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


foo = new FiveDMatrix(); foo.get(0).get(0).get(0).get(0).set(0,1);จะดี (และไม่เลวร้ายยิ่งกว่าfoo[0][0][0][0][0] = 1) ... และสถานการณ์อื่น ๆ อีกมากมายที่สิ่งนั้นไม่ละเมิด LoD

@MichaelT เมื่อคุณเริ่มเข้าสู่เมทริกซ์ของมิตินั้นดูเหมือนว่ามันจะง่ายกว่าที่จะปฏิบัติกับดัชนีเป็นเวกเตอร์ / tuple / array เองและปล่อยให้ internals ของคลาสเมทริกซ์กังวลเกี่ยวกับวิธีการจัดเก็บข้อมูลจริง (ซึ่งตอนนี้ฉันคิดว่ามันเป็นกฎหมายของ Demeter อย่างน้อยก็เกี่ยวข้องกับการห่อหุ้ม)
JAB

(และแน่นอนว่าการฝึกฝนแบบนั้นทำให้ง่ายต่อการใช้การแบ่งหลายมิติและมีเครื่องมือเมทริกซ์ที่ทรงพลังจริงๆ)
JAB

1
@JAB ฉันแค่พยายามหาตัวอย่าง สิ่งที่ดีกว่าน่าจะเป็นDom file = prase("some.xml"); file.get(tag1).getChild().get(tag2).getChild() ...- มันเป็นปัญหาของการประมวลผลโครงสร้างของรหัสใบ้บางอย่าง มันไม่ใช่คนแปลกหน้า ... มันโง่ไปหมด .?กลายเป็นมากประโยชน์ในโครงสร้างดังกล่าว

10

เรียงจาก

หากคุณเข้าใช้เพียงครั้งเดียว ( a?.Foo) คุณจะเทียบเท่ากับ:

a == null ? null : a.Foo

ซึ่งคนส่วนใหญ่จะเห็นด้วยไม่ได้เป็นการละเมิดกฎหมายของ Demeter ณ จุดนั้นมันเป็นเพียงน้ำตาล syntactic เพื่อปรับปรุงการอ่าน

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

ที่กล่าวมาเป็นสิ่งที่ควรค่าแก่การจดจำว่ากฎหมายของ Demeter ไม่ใช่กฎหมายต่อ se แต่เป็นแนวทางมากกว่า รหัสจำนวนมากละเมิดและทำงานได้ดี บางครั้งความเรียบง่ายของการออกแบบหรือรหัสมีค่ามากกว่าความเสี่ยงที่เกิดจากการละเมิดกฎหมายของ Demeter


อะไรมากกว่านั้นไม่จำเป็นต้องทำลาย LoD เช่นรูปแบบการสร้าง
jk

@Telastyn: ไวยากรณ์ภาษาใหม่ที่เรากำลังพูดถึงไม่สนับสนุนการเรียกเมธอด: a?.Func1(x)?.Func2(y) ตัวดำเนินการรวมศูนย์ว่างเป็นอย่างอื่น
Ben Voigt

@ BenVoigt - อ่าฉันกำลังออกบทความซึ่งระบุว่ามันใช้ได้กับฟิลด์คุณสมบัติและตัวทำดัชนีเท่านั้น ฉันไม่ได้ใช้ MSVS2015 ในการทดสอบ คุณพูดถูก
Telastyn

1
a. .Foo ไม่เทียบเท่ากับ == null? null: a.Foo อดีตประเมินเพียงครั้งเดียวหลังจะประเมินสองครั้ง นั่นอาจสำคัญหาก a เป็นตัววนซ้ำ
Loren Pechtel

9

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

ด้วยตัวเอง.?Aขึ้นอยู่กับจำนวนความรู้ในชั้นเรียนเท่ากันค่าซ้ายคือและชนิดที่ส่งคืนโดยวิธีการเช่นเดียวกับ.A != nullได้แก่ มันจำเป็นต้องรู้เกี่ยวกับAคุณสมบัติที่มีอยู่และส่งกลับค่าที่สามารถเปรียบเทียบnullได้

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

var x = A?.B?.C?.D?.E?.Fตอนนี้ให้พิจารณา

ซึ่งหมายความว่าAจะต้องเป็นประเภทที่อาจเป็นโมฆะหรืออาจมีBคุณสมบัติซึ่งจะต้องเป็นประเภทที่อาจเป็นโมฆะหรือมีCคุณสมบัติและอื่น ๆ จนกว่าประเภทของEทรัพย์สินที่เป็นสิ่งที่อาจเป็นโมฆะหรือ อาจมีFทรัพย์สิน

กล่าวอีกนัยหนึ่งเราต้องดำเนินการนี้ด้วยภาษาที่พิมพ์แบบคงที่หรือใช้ข้อ จำกัด กับประเภทที่สามารถส่งคืนได้หากการพิมพ์หลวม C # ส่วนใหญ่ใช้การพิมพ์แบบสแตติกดังนั้นเราจึงไม่ได้เปลี่ยนแปลงอะไรเลย

หากเรามีรหัสต่อไปนี้ก็จะละเมิดกฎหมาย:

ExplicitType x;
var b = A.B;
if (b == null)
  x = null;
else
{
  var c = b.C;
  if (c == null)
    x = null;
  else
  {
    var d = c.D;
    if (d == null)
      x = null;
    else
    {
      var e = d.E;
      if (e == null)
        x = null;
      else
        x = e.F;
    }
  }
}

ซึ่งเป็นเหมือนกัน รหัสนี้ที่ใช้การเชื่อมต่อขององค์ประกอบที่แตกต่างกันจำเป็นต้อง "รู้" เกี่ยวกับการมีเพศสัมพันธ์อย่างเต็มรูปแบบ แต่เป็นการใช้รหัสที่ไม่ละเมิดกฎหมายของ Demeter ที่จะทำเช่นนั้นโดยแต่ละหน่วยมีการเชื่อมต่อที่กำหนดไว้อย่างดีด้วย ต่อไป.


3
+1 ผู้ประกอบการใหม่เป็นเพียงน้ำตาล syntactic สำหรับสูตรขมที่คุณอธิบาย
Ross Patterson

1
ถ้านักพัฒนาเขียนรหัสที่ดูเหมือนว่าฉันคิดว่ามันง่ายกว่าที่จะสังเกตเห็นว่ามีบางอย่างไม่ถูกต้อง ฉันรู้ว่าโอเปอเรเตอร์เป็นน้ำตาล syntatic 100% แต่ถึงกระนั้นฉันคิดว่าผู้คนมักจะได้รับความสะดวกสบายมากขึ้นในการเขียนอะไรบางอย่างที่var x = A?.B?.C?.D?.E?.Fมากกว่า / ถ้าฉัน / เอลแม้ว่าพวกเขาจะเหมือนกันในตอนท้าย
Arthur Rizzo

2
ง่ายกว่าที่จะสังเกตเห็นบางสิ่งที่ไม่ถูกต้องA?.B?.C?.D?.E?.Fเพราะมีสิ่งที่ผิดน้อยกว่า เราควรพยายามFผ่านเส้นทางนั้นหรือไม่ควรขณะที่แบบฟอร์มที่ยาวกว่าอาจมีข้อผิดพลาดอยู่ในนั้นและข้อผิดพลาดของมันไม่ใช่สิ่งที่ถูกต้อง
Jon Hanna

@ArthurRizzo แต่ถ้าคุณเชื่อมโยงโค้ดข้างต้นกับการละเมิด LoD คุณก็จะพลาดได้ง่ายในกรณีที่ไม่จำเป็นต้องมีการตรวจสอบว่างA.B.C.Dเปล่าและคุณสามารถทำได้ มันง่ายกว่ามากที่จะมีสิ่งเดียวที่ต้องระวัง (การเข้าถึงทรัพย์สินที่ถูกล่ามโซ่) มากกว่าสองสิ่งที่แตกต่างกันซึ่งขึ้นอยู่กับรายละเอียดที่ไม่เกี่ยวข้องสวย (การตรวจสอบ null)
Ben Aaronson

5

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

วัตถุที่สร้างขึ้นเพื่อวัตถุประสงค์ในการห่อหุ้มพฤติกรรม (ไม่ว่าจะใช้ร่วมกันหรือไม่) หรือสำหรับการใช้ร่วมกับรหัสภายนอก (ไม่ว่าพวกเขาจะห่อหุ้มพฤติกรรมหรือข้อมูล) โดยทั่วไปควรจะเข้าถึงได้ผ่านพื้นผิวอินเตอร์เฟส เมื่อวัตถุที่เก็บข้อมูลถูกสร้างขึ้นเพื่อการใช้งานโดยผู้สร้างของพวกเขาเท่านั้นเหตุผลของกฎหมาย -Demeter ปกติสำหรับการหลีกเลี่ยงการเข้าถึง "ลึก" ไม่ได้ใช้ หากส่วนหนึ่งของคลาสที่จัดเก็บหรือจัดการข้อมูลในวัตถุมีการเปลี่ยนแปลงในลักษณะที่จะต้องมีการปรับรหัสอื่น ๆ มันจะเป็นไปได้ที่จะรับประกันได้ว่ารหัสดังกล่าวทั้งหมดได้รับการปรับปรุงเพราะ - ดังที่ระบุไว้ข้างต้น - วัตถุถูกสร้างขึ้น การใช้เอกสิทธิ์ของชั้นหนึ่ง

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


ทำไมกฎหมายของ Demeter จึงไม่ใช้กับวัตถุที่เก็บข้อมูล?
Telastyn

2
@Telastyn: วัตถุประสงค์ของ LoD คือการหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นหากมีชิ้นส่วนของรหัสเข้าถึงวัตถุภายในที่อย่างอื่นอาจจัดการหรือดูแลเกี่ยวกับ หากไม่มีสิ่งใดในเอกภพที่อาจจัดการหรือดูแลเกี่ยวกับสถานะของวัตถุชั้นในได้ดังนั้นไม่จำเป็นต้องป้องกันปัญหาดังกล่าว
supercat

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

@Telastyn: จุดของคุณเกี่ยวกับเส้นทางเป็นสิ่งที่ดี แต่ฉันคิดว่าจุดของฉันถือได้ดี การเข้าถึงวัตถุผ่านหลายเส้นทางจะสร้างการเชื่อมต่อระหว่างเส้นทางเหล่านั้น หากการเข้าถึงบางอย่างผ่านทางตื้น ๆ การเข้าถึงผ่านทางลึกนั้นอาจทำให้เกิดการมีเพศสัมพันธ์ที่ไม่ต้องการ หากการเข้าถึงทั้งหมดผ่านเส้นทางลึกหนึ่งเส้นทางใดเส้นทางหนึ่งจะไม่มีเส้นทางใดที่จะเชื่อมโยงไปถึง
supercat

@Telastyn เป็นเรื่องดีมากที่จะสำรวจโครงสร้างข้อมูลเพื่อรับข้อมูลที่ลึกลงไป มันไม่เหมือนกับการเรียกเมธอดซ้อน บางครั้งคุณจำเป็นต้องรู้โครงสร้างข้อมูลและวิธีการซ้อนกัน แต่ไม่เหมือนกันกับวัตถุเช่นบริการและบริการ / ที่เก็บซ้อนเป็นต้น
ต่อHornshøj-Schierbeck
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.