C # อ่านยากขึ้นไหม


15

เมื่อ C # ได้รับการพัฒนาคุณสมบัติด้านภาษาจำนวนมากได้ถูกเพิ่ม มันมาถึงจุดที่มันกลายเป็นอ่านไม่ได้สำหรับฉัน

ยกตัวอย่างเช่นพิจารณารหัสต่อไปนี้จากรหัส Caliburn.Micro ที่นี่ :

            container = CompositionHost.Initialize(
                   new AggregateCatalog(
                      AssemblySource.Instance.
                             Select(x => new AssemblyCatalog(x))
                               .OfType<ComposablePartCatalog>()
                )
            );

ตอนนี้เป็นเพียงตัวอย่างเล็ก ๆ

ฉันมีคำถามจำนวนหนึ่ง:

  • นี่เป็นปัญหาทั่วไปหรือเป็นที่รู้จักหรือไม่?
  • ชุมชน C # ค้นหาเหมือนกันหรือไม่
  • นี่เป็นปัญหาเกี่ยวกับภาษาหรือเป็นสไตล์ที่นักพัฒนาใช้หรือไม่

มีวิธีง่ายๆในการเข้าใจโค้ดอื่น ๆ และหลีกเลี่ยงการเขียนโค้ดด้วยวิธีนี้หรือไม่?


6
มันเป็นฟังก์ชั่นแลมบ์ดาที่อ่านยากจนกว่าคุณจะได้มันมาจริงๆ
Ryathal

9
ฉันคิดว่าคุณไม่รู้จักไวยากรณ์เช่นเดียวกับที่คุณคิด ด้วยการฝึกฝนการอ่านตัวอย่างของคุณเป็นเรื่องง่าย
ChaosPandion

6
@Thomas Owens: คนอึบริสุทธิ์อย่างน้อยทำให้เรามีบางเวลาที่จะแก้ไขคำถามเพื่อให้พวกเขาเปิด 15 นาที? มาเดี๋ยวนี้.
Steven Evers

4
@DannyVarod: 1 "ไม่" ไม่ได้เป็นคำตอบที่ได้รับการยอมรับ 2. คำถามนี้ปิดให้บริการ 3. หากคุณยอมรับว่าคำถามที่ไม่ควรจะอยู่ที่นี่แล้วธง / การลงคะแนนเสียงเพื่อปิดหรือแก้ไขมันจะดีกว่า
Steven Evers

2
@ Thorbjørn Ravn Andersen - ใครจะเรียนรู้ได้จากตบ? ไม่มีข้อมูล!

คำตอบ:


12

ทราบอย่างรวดเร็วในการที่ภาษาที่ควรจะชัดเจนขึ้น: C # เป็นภาษาโปรแกรมที่ใช้งานทั่วไป ; ซึ่งแตกต่างจาก C (เช่น C ++) มันมุ่งมั่นเพื่อให้เป็นนามธรรมสูง ซึ่งแตกต่างจากภาษา Lisp ที่มันมีจุดมุ่งหมายเพื่อการแสดงออกที่เป็นจริงและแตกต่างจาก Java มันเป็นแรงผลักดันมากขึ้น - Microsoft เป็นอย่างรวดเร็วเพื่อตอบสนองความต้องการ

นั่นคือเหตุผลที่มันกลายเป็นส่วนผสมของ LINQ, lambdas และคำหลักแปลกใหม่ - มันปรับตัวเข้ากับโดเมนปัญหาใหม่ได้อย่างรวดเร็วและนี่คือความลาดชันที่ลื่นไหลไปสู่ภาษาที่ซับซ้อนจนมีน้อยมากที่สามารถใช้ได้อย่างถูกต้อง (เช่น C ++) มันไม่ใช่ปัญหาของ C # แต่เป็นปัญหากับภาษาใด ๆ ที่มีเป้าหมายที่ทะเยอทะยานเหล่านี้

ชุมชนตระหนักถึงสิ่งนี้และที่สำคัญกว่านั้นคนที่อยู่เบื้องหลัง C # ได้ตระหนักถึงสิ่งนี้อย่างถี่ถ้วน (รายการบล็อกและพอดคาสต์สองสามรายการที่อยู่เบื้องหลังการเพิ่มใหม่ใน C # 5.0 แสดงให้เห็นว่า Microsoft กำลังพยายามโหลดบางส่วนออกจากเรือธงของพวกเขาเพื่อที่จะไม่กลายเป็น tarpit: การแนะนำของ DLR, สปอตไลท์ที่สดใสกว่าภาษาใหม่ (F #)

ยิ่งกว่านั้นเนื้อหาของหลักสูตรใน C # (รวมถึงการรับรอง MS) แนะนำรูปแบบการใช้ C # ที่แตกต่างกัน (แต่สอดคล้องกัน) ขึ้นอยู่กับปัญหา - เลือกอาวุธของคุณและติดมัน: LINQ สไตล์คล่องแคล่วในปัญหาบางอย่าง - เก่าแก่ที่สุด


2
คุณสามารถอธิบายสิ่งที่คุณหมายถึงด้วย "แตกต่างจากภาษาเสียงกระเพื่อมมันมีจุดมุ่งหมายเพื่อการแสดงออกทางปฏิบัติ"?
Giorgio

27

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

ให้นำสองตัวอย่างทั้งสองตามตัวอย่างที่พบใน StackOverflow เกี่ยวกับปัญหาเดียวกันโดยการค้นหาประเภทที่มีแอตทริบิวต์เฉพาะ:

C # 2.0:

static IEnumerable<Type> GetTypesWithAttribute<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{
    foreach(Assembly assembly in AppDomain.Current.GetAssemblies())
    {
        foreach(Type type in assembly.GetTypes()) 
        {
            if (type.IsDefined(typeof(TAttribute),inherit))
                yield return type;
        }
    }
}

C # 4.0:

IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{ 
    return from assembly in AppDomain.CurrentDomain.GetAssemblies()
           from type in assembly.GetTypes()
           where type.IsDefined(typeof(TAttribute),inherit)
           select type;
}

IMHO ไวยากรณ์ใหม่ทำให้อ่านง่ายขึ้นมาก


ไวยากรณ์ใหม่นั้นง่ายต่อการอ่าน แต่ง่ายต่อการเข้าใจเช่นเดียวกับสิ่งที่เกิดขึ้นภายใต้ประทุน? ตัวอย่างแรกเข้าใจได้ง่ายตัวอย่างที่สองอ่านได้ง่ายขึ้น
nawfal

4
@nawfal จากประสบการณ์ของฉันผู้คนมีปัญหาในการทำความเข้าใจ "การคืนผลตอบแทน" มากกว่าการสร้างคำสั่ง linq; ดังนั้นฉันจะโต้แย้งที่สองสามารถอ่านและเข้าใจได้ง่ายขึ้น ทั้งไม่ได้บอกคุณว่าเกิดอะไรขึ้นภายใต้ประทุนเนื่องจากแผนที่ทั้งคู่ไปยัง abstractions ไกลจากการทำงานของโปรเซสเซอร์
Chuu

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

8

เมื่อเพิ่ม LINQ มันจะทำให้รูปแบบของการเข้ารหัสที่เกี่ยวข้องกับการผูกมัดวิธีการสไตล์ Fluent จำนวนมากและการส่งผ่านของ lambdas เป็นพารามิเตอร์

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

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

var assemblyCatalog = AssemblySource.Instance
    .Select(x => new AssemblyCatalog(x))
    .OfType<ComposablePartCatalog>();
var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
container = CompositionHost.Initialize(aggregateCatalog);

1
แปลกไหมที่จะสร้างรูปแบบใหม่แล้วเปลี่ยนรูปแบบนั้นทันทีหลังจากนั้น
DeadMG

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

ฉันจะโทษสำหรับการเยื้อง :() นี่คือต้นฉบับ: devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/…

1
ฉันเห็นด้วยอย่างยิ่งกับคำตอบนั้น ปัญหาในส่วนตัวอย่างของรหัสไม่ใช่ไวยากรณ์ C # ใหม่ซึ่งผู้เขียนพยายามที่จะฉลาดด้วยรหัส "หนึ่งซับ" มีกฎเก่านี้ย้อนกลับมาจากยูนิกซ์ทุกอย่างควรทำสิ่งเดียวและทำได้ดี มันใช้กับคลาสมันใช้กับเมธอดและแน่นอนที่สุดมันใช้กับบรรทัดของโค้ด
Laurent Bourgault-Roy

4

รหัสในตัวอย่างของคุณไม่สามารถอ่านได้ง่ายเพราะ

  • มันผสมผสานหลายแนวคิด (Composition, Catalogs, Aggregates, Assemblies, ComposableParts ... ) กับการซ้อนหลายระดับในขณะที่รหัสการโทรควรจะจัดการกับระดับเดียวเท่านั้น ดูเหมือนว่าเป็นการละเมิดกฎของ Demeter เท่านั้นด้วยการเรียกใช้เมธอดซ้อนแทนที่จะเป็นสายย่อยของคุณสมบัติย่อย นี่เป็นการรบกวนความตั้งใจที่อยู่เบื้องหลังบรรทัดของรหัสบ้าง

  • มีการใช้งานซิงเกิลแปลก ๆ - AssemblySource.Instance.Select()หมายความว่าอินสแตนซ์เป็น IEnumerable ซึ่งค่อนข้างอึดอัดใจ

  • ตัวแปร x ในนิพจน์แลมบ์ดานั้นน่าเกลียด โดยทั่วไปคุณพยายามให้แลมบ์ดาตัวแปรของคุณตั้งใจเปิดเผยชื่อ - ช่วยให้ผู้อ่านระบุประเภทของข้อมูลที่ใช้งานได้แม้ว่าเขาจะไม่คุ้นเคยกับแลมบ์ดาก็ตาม

  • ยังไม่ชัดเจนว่าทำไมคุณควรกรองด้วยOfType<T>()ชุดของวัตถุที่คุณเพิ่งปรับใหม่ ...

อย่างไรก็ตามข้อบกพร่องเหล่านี้เกี่ยวข้องกับวิธีการที่นักพัฒนาดั้งเดิมเขียนรหัสและวิธีการที่เขาออกแบบให้เป็น นี่ไม่ใช่สิ่งที่เฉพาะเจาะจงสำหรับเวอร์ชันล่าสุดของ C # และลักษณะของแลมบ์ดานิพจน์

โดยทั่วไปแล้วจะช่วยในกรณีที่ผู้อ่านรหัสของคุณรู้ว่า lambdas ทำงานอย่างไร แต่ด้วยการตั้งชื่อที่ชัดเจนเพียงพอคุณเกือบจะจัดการเพื่อทำให้โค้ดของคุณสามารถอ่านได้แม้กับคนที่มีพื้นหลัง pre-.NET 3.5


2

เมื่อใดก็ตามที่ภาษายอดนิยมรุ่นใหม่ได้รับการสร้างใหม่การอภิปรายที่คล้ายกันก็จะเกิดขึ้น

ฉันยังมีข้อสงสัยเหล่านี้เมื่อหลายปีก่อน (http://gsscoder.blogspot.it/2009/08/use-csharps-features-wise.html)

ในความคิดของฉัน C # มีการพัฒนาในลักษณะที่สวยงามและสอดคล้องกัน

โค้ดในตัวอย่างของคุณไม่ซับซ้อนบางทีคุณอาจไม่ได้ใช้กับการแสดงออกแลมด้า

ปัญหาคือ C # ไม่เพียง แต่เป็นภาษาเชิงวัตถุเท่านั้นตอนนี้ยังรองรับโครงสร้างที่ใช้งานได้ (http://archive.msdn.microsoft.com/FunctionalCSharp/)


1

ฉันใช้เวลาซักครู่เพื่อทำความเข้าใจกับไวยากรณ์ของแลมบ์ดาและฉันมาจากภูมิหลังทางคณิตศาสตร์และฟิสิกส์ มันคล้ายกับการแสดงออกทางคณิตศาสตร์เล็กน้อยพวกเขาใช้ -> แทน =>:

ตัวอย่างคณิตศาสตร์ f (x): = x-> x + 2 สิ่งนี้อ่านเป็น "ฟังก์ชั่น f ของ x ถูกกำหนดให้เป็นแผนที่ x เพื่อ x + 2

c # example del myDelegate = x => x +2; สิ่งนี้อ่านว่า "myDelegate เป็นฟังก์ชั่นที่ myDelegate (x) แม็พ x on to x + 2

ความไม่ลงรอยกันระหว่างคณิตศาสตร์และการเขียนโปรแกรมไม่ได้ช่วยจริงๆแม้ว่าฉันคิดว่า -> ได้ถูกนำขึ้นใน C ++ ในฐานะ "คุณสมบัติของ" (urrgghh!)

http://en.wikipedia.org/wiki/List_of_mathematical_symbols


"แม้ว่าฉันคิดว่า -> ถูกใช้ใน C ++ เป็น" คุณสมบัติของ "(urrgghh!) แล้ว"ราวกับว่า! ไม่ดีใน C ++ หมายถึง "คุณสมบัติของการจัดสรรแบบไดนามิก ... " หากบางสิ่งไม่ใช่ไดนามิกคุณใช้ช่วงเวลาเหมือนในภาษาอื่นทุกภาษา
mg30rg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.