การสะท้อนชื่อพารามิเตอร์: การใช้ C # lambda หรือการใช้ไวยากรณ์ที่ไม่เหมาะสม?


428

ฉันกำลังดูส่วนประกอบของMvcContrib Grid และฉันก็รู้สึกทึ่ง แต่ในเวลาเดียวกันกลับกลายเป็นว่าเป็นกลอุบายที่ใช้ในไวยากรณ์ไวยากรณ์ :

.Attributes(style => "width:100%")

ไวยากรณ์ข้างต้นชุดแอตทริบิวต์รูปแบบของ HTML width:100%สร้างขึ้นเพื่อ ตอนนี้ถ้าคุณให้ความสนใจ 'สไตล์' ไม่ได้ระบุไว้ถูกอนุมานจากชื่อของพารามิเตอร์ในการแสดงออก! ฉันต้องขุดลงไปและพบว่ามี 'เวทมนตร์' เกิดขึ้น:

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

ดังนั้นรหัสจึงใช้ชื่อทางการของพารามิเตอร์เพื่อสร้างพจนานุกรมของคู่ของค่าชื่อแอตทริบิวต์ โครงสร้างไวยากรณ์ที่ได้นั้นมีความหมายชัดเจนมาก แต่ในเวลาเดียวกันก็อันตรายมาก การใช้แลมบ์ดานิพจน์ทั่วไปช่วยให้สามารถแทนที่ชื่อที่ใช้โดยไม่มีผลข้างเคียง ผมเห็นตัวอย่างในหนังสือที่บอกว่าcollection.ForEach(book => Fire.Burn(book))ฉันรู้ว่าฉันสามารถเขียนในรหัสของฉันcollection.ForEach(log => Fire.Burn(log))และมันหมายถึงสิ่งเดียวกัน แต่ด้วยไวยากรณ์ MvcContrib Grid ที่นี่ทั้งหมดในทันทีฉันพบรหัสที่มีลักษณะและการตัดสินใจตามชื่อที่ฉันเลือกสำหรับตัวแปรของฉัน!

ดังนั้นนี่คือการปฏิบัติร่วมกันกับชุมชน C # 3.5 / 4.0 และคนรักการแสดงออกแลมบ์ดา? หรือเป็นคนหลอกลวงที่หลอกลวงคนหนึ่งที่ฉันไม่ควรกังวลอะไร?


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

190
ฉันเพิ่งถาม Anders (และทีมออกแบบที่เหลือ) สิ่งที่พวกเขาคิด สมมติว่าผลลัพธ์จะไม่สามารถพิมพ์ในหนังสือพิมพ์ที่เหมาะสำหรับครอบครัวได้
Eric Lippert

22
C # ปัจจุบันไม่มีไวยากรณ์ที่สะอาดและเบาสำหรับแผนที่โดยเฉพาะแผนที่ที่ส่งผ่านไปยังฟังก์ชั่น ภาษาไดนามิกต่าง ๆ (Ruby, Python, JavaScript, ColdFusion 9) มีไวยากรณ์ที่สะอาดและสว่างสำหรับสิ่งนั้นสำหรับบางส่วนขยายหรืออย่างอื่น
yfeldblum

28
โอ้ฉันคิดว่ามันดูน่ายินดี สำหรับไวยากรณ์สำหรับแผนที่ใช่มันจะดีมากถ้าเราสามารถสร้างใหม่ {{"Do", "A Deer"}, {"Re", "Golden sun"} ... } และให้คอมไพเลอร์อนุมาน การสร้างแผนที่เหมือนใหม่ [] {1, 2,3} infers การสร้างอาร์เรย์ int เรากำลังพิจารณาสิ่งต่าง ๆ เหล่านี้
Eric Lippert

17
Eric Lippert ฉันเคารพคุณมาก แต่ฉันคิดว่าคุณและกลุ่ม (รวมถึง Anders ที่ฉันนับถือ FREAKIN 'TREMENDOUSLY) กำลังกระแทกอย่างรุนแรงเช่นนี้ ในขณะที่คุณยอมรับ C # ไม่มีไวยากรณ์ที่แน่นหนาสำหรับแผนที่และภาษาอื่น ๆ (เช่น Ruby) มีดีมาก ชายคนนี้พบวิธีรับไวยากรณ์ที่เขาต้องการ ฉันจะให้คุณมีวิธีที่คล้ายกันในการแสดงว่ามันเกือบจะเป็นแสดงออกเป็นไวยากรณ์ของเขาด้วยข้อเสียน้อยลง แต่ไวยากรณ์และความจริงที่ว่าเขาทำงานอย่างหนักเพื่อให้ชัดเจนแสดงให้เห็นถึงความจำเป็นในการพัฒนาภาษา ประสิทธิภาพที่ผ่านมาบ่งบอกว่าพวกคุณจะสร้างสิ่งที่ยอดเยี่ยมสำหรับมัน
Charlie ดอกไม้

คำตอบ:


147

สิ่งนี้มีการทำงานร่วมกันที่ไม่ดี ตัวอย่างเช่นลองพิจารณาตัวอย่าง C # - F # นี้

ค#:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F #:

Class1.Foo(fun yadda -> "hello")

ผลลัพธ์:

พิมพ์ "arg" (ไม่ใช่ "yadda")

ดังนั้นผู้ออกแบบห้องสมุดควรหลีกเลี่ยง 'การละเมิด' ชนิดนี้หรืออย่างน้อยก็ให้การโอเวอร์โหลด 'มาตรฐาน' (เช่นที่ใช้ชื่อสตริงเป็นพารามิเตอร์เสริม) หากพวกเขาต้องการมีการทำงานร่วมกันที่ดีในภาษา. Net


11
คุณทำไม่ได้ กลยุทธ์นี้ไม่สามารถพกพาได้ (ในกรณีที่ช่วยได้ตัวอย่างเช่นวิธีอื่น ๆ F # อาจมีวิธีการโอเวอร์โหลดที่แตกต่างกันเฉพาะในประเภทย้อนกลับ (การอนุมานประเภทสามารถทำได้) ซึ่งสามารถแสดงใน CLR แต่ F # ไม่อนุญาตส่วนใหญ่เพราะถ้า คุณทำอย่างนั้น APIs เหล่านั้นจะไม่สามารถเรียกใช้ได้จาก C #) เมื่อพูดถึงการทำงานร่วมกันจะมีการแลกเปลี่ยนคุณสมบัติของ 'edge' เสมอเกี่ยวกับประโยชน์ที่คุณจะได้รับเมื่อเทียบกับสิ่งที่คุณทำงานร่วมกัน
Brian

32
ฉันไม่ชอบการทำงานร่วมกันที่ไม่ใช่เหตุผลที่จะไม่ทำอะไร หากการทำงานร่วมกันเป็นข้อกำหนดแล้วถ้าเป็นเช่นนั้นทำไมต้องเป็นห่วง? นี่คือ YAGNI IMHO
John Farrell

15
@jfar: ใน. NET CLR การทำงานร่วมกันของที่ดินมีมิติใหม่ทั้งหมดเนื่องจากชุดประกอบที่สร้างขึ้นในคอมไพเลอร์ใด ๆควรจะถูกใช้จากภาษาอื่น
Remus Rusanu

25
ฉันยอมรับว่าคุณไม่จำเป็นต้องปฏิบัติตาม CLS แต่ดูเหมือนว่าเป็นความคิดที่ดีถ้าคุณกำลังเขียนไลบรารีหรือตัวควบคุม (และตัวอย่างข้อมูลที่เริ่มต้นนี้มาจากกริดใช่หรือไม่) มิฉะนั้นคุณจะ จำกัด ฐานผู้ชม / ลูกค้าของคุณ
JMarsch

4
อาจจะคุ้มค่าที่จะเปลี่ยน: Func <object, string> เป็น Expression << Func <object, string >> และถ้าคุณ จำกัด ทางด้านขวามือของนิพจน์ให้เป็นค่าคงที่คุณสามารถมีการนำไปปฏิบัติเช่นนี้: <string, string> Hash (params Expression <Func <object, string >> [] hash) {Dictionary <string, string> values ​​= new dictionary <string, string> (); foreach (var func in hash) {values ​​[func.Parameters [0] .Name] = (สตริง) ((ConstantExpression) func.Body) .Value; } คืนค่า; }
davidfowl

154

ผมพบว่าแปลกไม่มากเพราะชื่อแต่เพราะแลมบ์ดาไม่จำเป็น ; มันสามารถใช้แบบไม่ระบุชื่อและยืดหยุ่นได้มากกว่า:

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

นี่คือรูปแบบที่ใช้ใน ASP.NET MVC ส่วนใหญ่ (และตัวอย่าง) และมีการใช้งานอื่น ๆ ( ข้อควรจำโปรดทราบความคิดของ Ayende ด้วยหากชื่อนั้นเป็นค่าเวทย์มนตร์แทนที่จะเป็นเฉพาะผู้โทร)


4
สิ่งนี้ยังมีปัญหาการทำงานร่วมกัน ไม่ใช่ทุกภาษาที่รองรับการสร้างประเภทที่ไม่ระบุตัวตนเช่นนั้นได้ทันที
Brian

5
ฉันรักที่ไม่มีใครตอบคำถามจริง ๆ แทนที่จะให้ผู้คนโต้แย้งว่า "นี่ดีกว่า" : p มันเป็นการละเมิดหรือไม่?
Sam Saffron

7
ฉันสนใจที่จะเห็นปฏิกิริยาของ Eric Lippert ต่อเรื่องนี้ เพราะมันอยู่ในกรอบรหัส และมันก็น่ากลัวเหมือนกัน
Matt Hinze

26
ฉันไม่คิดว่าปัญหาจะอ่านได้หลังจากเขียนโค้ดแล้ว ฉันคิดว่าปัญหาที่แท้จริงคือความสามารถในการเรียนรู้ของรหัส คุณมีอะไรจะคิดว่าเมื่อ IntelliSense ของคุณว่า.Attributes (วัตถุ obj) ? คุณจะต้องอ่านเอกสารประกอบ (ซึ่งไม่มีใครอยากทำ) เพราะคุณไม่รู้ว่าต้องผ่านวิธีใด ฉันไม่คิดว่านี่จะดีไปกว่าตัวอย่างในคำถาม
NotDan

2
@Annis - ทำไมมีความยืดหยุ่นมากกว่า: มันไม่ได้ใช้ชื่อพารามิเตอร์โดยนัยซึ่งอาจ (ไม่พูดถึงฉัน) ทำให้เกิดปัญหากับการใช้แลมบ์ดา (ภาษาอื่น ๆ ) - แต่คุณยังสามารถใช้วัตถุปกติที่มีคุณสมบัติที่กำหนด ตัวอย่างเช่นคุณอาจมีHtmlAttributesคลาสที่มีคุณลักษณะที่คาดหวัง (สำหรับ intellisense) และเพียงแค่ละเว้นnullคลาสที่มีค่า ...
Marc Gravell

137

แค่อยากจะโยนความคิดของฉัน (ฉันเป็นผู้เขียนองค์ประกอบกริด MvcContrib)

นี่เป็นการละเมิดทางภาษาอย่างแน่นอน - ไม่ต้องสงสัยเลยว่า อย่างไรก็ตามฉันไม่คิดว่ามันขัดกับสัญชาตญาณจริงๆ - เมื่อคุณดูการโทรหาAttributes(style => "width:100%", @class => "foo")
ฉันคิดว่ามันค่อนข้างชัดเจนว่าเกิดอะไรขึ้น จากมุมมองของ Intellisense ฉันเห็นว่ามันค่อนข้างทึบ

สำหรับผู้ที่สนใจข้อมูลพื้นฐานบางอย่างเกี่ยวกับการใช้งานใน MvcContrib ...

ฉันเพิ่มสิ่งนี้ลงในกริดตามความชอบส่วนตัว - ฉันไม่ชอบการใช้งานประเภทที่ไม่ระบุตัวตนเป็นพจนานุกรม (มีพารามิเตอร์ที่ใช้ "วัตถุ" เป็นทึบแสงเช่นเดียวกับที่ใช้ params Func []) และ initializer คอลเลกชันพจนานุกรมคือ ค่อนข้าง verbose (ฉันไม่ได้เป็นแฟนของอินเตอร์เฟซคล่องแคล่ว verbose เช่นมีสายเข้าด้วยกันหลายสายไปยังแอตทริบิวต์ ("สไตล์", "display: none") แอตทริบิวต์ ("class", "foo") ฯลฯ )

ถ้า C # มีไวยากรณ์ verbose น้อยกว่าสำหรับตัวอักษรพจนานุกรมดังนั้นฉันจะไม่ต้องใส่ใจรวมถึงไวยากรณ์นี้ในองค์ประกอบกริด :)

ฉันยังต้องการชี้ให้เห็นว่าการใช้งาน MVCContrib นี้เป็นทางเลือกอย่างสมบูรณ์ - นี่เป็นวิธีการขยายที่ตัดการโอเวอร์โหลดที่ใช้ IDictionary แทน ฉันคิดว่ามันเป็นสิ่งสำคัญที่หากคุณให้วิธีการเช่นนี้คุณควรสนับสนุนวิธีการที่ 'ปกติ' มากขึ้นเช่นสำหรับการใช้ภาษาอื่น ๆ

นอกจากนี้มีคนพูดถึง 'ภาพสะท้อนค่าโสหุ้ย' และฉันแค่ต้องการชี้ให้เห็นว่าวิธีการนี้มีค่าใช้จ่ายไม่มาก - ไม่มีการสะท้อนแบบไทม์หรือการรวบรวมการแสดงออกที่เกี่ยวข้อง (ดูhttp://blog.bittercoder.com /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx )


1
ฉันยังพยายามที่จะแก้ไขปัญหาที่เกิดขึ้นในบล็อกของฉัน: jeremyskinner.co.uk/2009/12/02/lambda-abuse-the-mvccontrib-hash
Jeremy Skinner

4
ไม่มีความทึบแสงใน Intellisense น้อยกว่าวัตถุที่ไม่ระบุตัวตน
แบรดวิลสัน

22
+1 สำหรับการกล่าวขวัญว่าอินเตอร์เฟซจะถูกเพิ่มผ่านทางตัวเลือกวิธีการขยาย ผู้ใช้ที่ไม่ใช่ C # (และใครก็ตามที่ถูกละเมิดโดยการใช้ภาษา) สามารถละเว้นการใช้งานได้
Jørn Schou-Rode

50

ฉันต้องการ

Attributes.Add(string name, string value);

มันชัดเจนและเป็นมาตรฐานมากกว่าและไม่มีอะไรได้มาจากการใช้ lambdas


20
มันเป็นอย่างไร html.Attributes.Add("style", "width:100%");ไม่ได้อ่านเหมือนกันstyle = "width:100%"(เป็น html จริงที่สร้างขึ้น) ในขณะที่style => "width:100%"ใกล้เคียงกับที่ปรากฏใน HTML ที่เป็นผลลัพธ์
Jamie Penney

6
ไวยากรณ์ของพวกเขาอนุญาตให้ใช้เทคนิคต่าง ๆ เช่น. คุณลักษณะ (id => 'foo', @class => 'bar', style => 'width: 100%') ลายเซ็นของฟังก์ชั่นใช้ไวยากรณ์ params สำหรับจำนวนตัวแปรของ args: คุณสมบัติ (params Func <object, object> [] args) มันมีประสิทธิภาพมาก แต่ฉันใช้เวลาพอสมควรที่จะเข้าใจว่ามันทำ
Remus Rusanu

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

17
อาจมีการใช้วัตถุที่ไม่ระบุชื่อเช่นกันโดยไม่เสียสละ "ความงาม" หรือไม่? .Attributes (ใหม่ {id = "foo", @class = "bar", style = "width: 100%"}) ??
Funka

10
@Guffa ทำไมมันเป็นเหตุผลที่ไม่ดีสำหรับการตัดสินใจออกแบบ? ทำไมพวกเขาถึงไม่เหมือนกันล่ะ? โดยเหตุผลที่พวกเขาควรมีลักษณะแตกต่างกันโดยเจตนา ? ฉันไม่ได้พูดผิดของคุณฉันแค่บอกว่าคุณอาจต้องการที่จะอธิบายประเด็นของคุณให้ละเอียดยิ่งขึ้น
Samantha Branham

45

ยินดีต้อนรับสู่ Rails Land :)

มันไม่มีอะไรผิดปกติกับมันตราบใดที่คุณรู้ว่าเกิดอะไรขึ้น (เมื่อชนิดของสิ่งนี้ไม่ได้บันทึกไว้อย่างดีว่ามีปัญหา)

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

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


3
ฉันลังเลเล็กน้อย แต่ฉันเห็นด้วย นอกเหนือจากค่าโสหุ้ยการสะท้อนไม่มีความแตกต่างอย่างมีนัยสำคัญระหว่างการใช้สตริงเช่นเดียวกับใน Add () กับการใช้ชื่อพารามิเตอร์แลมบ์ดา อย่างน้อยฉันก็นึกได้ คุณสามารถโคลนมันและพิมพ์ "sytle" โดยไม่สังเกตเห็นทั้งสองวิธี
Samantha Branham

5
ฉันไม่สามารถเข้าใจได้ว่าทำไมสิ่งนี้ถึงไม่แปลกสำหรับฉันแล้วฉันก็นึกถึง Rails : D
Allyn

43

มันน่ากลัวในระดับมากกว่าหนึ่ง และไม่นี่คือไม่มีอะไรเหมือนทับทิม มันเป็นการละเมิด C # และ. Net

มีข้อเสนอแนะมากมายเกี่ยวกับวิธีการทำสิ่งนี้ในลักษณะตรงไปตรงมามากขึ้น: tuples ประเภทที่ไม่ระบุชื่ออินเทอร์เฟซที่คล่องแคล่วและอื่น ๆ

สิ่งที่ทำให้มันเลวร้ายคือวิธีการที่จะจินตนาการถึงความดีของตัวเอง:

  • เกิดอะไรขึ้นเมื่อคุณต้องการเรียกสิ่งนี้จาก VB?

    .Attributes(Function(style) "width:100%")

  • ระบบ Intellisense ตอบโต้ได้อย่างสมบูรณ์แบบจะให้ความช่วยเหลือเล็กน้อยในการหาวิธีการส่งผ่านข้อมูล

  • มันไม่มีประสิทธิภาพโดยไม่จำเป็น

  • ไม่มีใครรู้ว่าจะดูแลมันได้อย่างไร

  • อะไรคือประเภทของการโต้แย้งไปสู่คุณลักษณะมันคือFunc<object,string>อะไร? ความตั้งใจนั้นเปิดเผยอย่างไร เอกสาร Intellisense ของคุณคืออะไรที่จะพูดว่า "โปรดเพิกเฉยต่อค่าทั้งหมดของวัตถุ"

ฉันคิดว่าคุณเป็นคนชอบธรรมที่มีความรู้สึกรังเกียจอย่างสมบูรณ์


4
ฉันจะบอกว่า - มันใช้งานง่ายอย่างสมบูรณ์ :)
Arnis Lapsa

4
คุณบอกว่าไม่มีอะไรเหมือนทับทิม แต่มันเป็นห่าที่น่ากลัวมากเช่นเดียวกับไวยากรณ์ของรูบี้สำหรับการระบุคีย์และค่าของ hashtable
ชาร์ลีดอกไม้

3
รหัสที่แตกต่างกันภายใต้การแปลงอัลฟา! yey!
Phil

3
@ Charlie, syntactically มันดูคล้ายกัน semantically มันแตกต่างกัน
Sam Saffron

39

ฉันอยู่ในค่าย "syntax brilliance" ถ้าพวกมันบันทึกไว้อย่างชัดเจนและมันดูเท่มาก ๆ มันก็แทบจะไม่มีปัญหาอะไรกับมันเลย!


10
อาเมนพี่ชาย เอเมน (ต้องการอาเมนที่ 2 เพื่อตอบสนองความยาวขั้นต่ำสำหรับความคิดเห็น :)
ชาร์ลีดอกไม้

ความคิดเห็นของคุณเพียงอย่างเดียวเป็นมากกว่าที่ต้องการ แต่จากนั้นคุณไม่สามารถเพียงแค่เอเมนเพียงครั้งเดียวและใส่ความคิดเห็นของคุณ: D
Sleeper Smith

37

เขาทั้งคู่. มันเป็นการลบล้างการแสดงออกแลมบ์ดาและความหมายของไวยากรณ์


16
ดังนั้นมันจึงเป็นการละเมิดไวยากรณ์ที่ยอดเยี่ยมของการแสดงออกแลมบ์ดา? ผมคิดว่าผมเห็นด้วย :)
เซท Petry จอห์นสัน

21

ฉันแทบจะไม่เคยเจอการใช้งานประเภทนี้ ฉันคิดว่ามัน "ไม่เหมาะสม" :)

นี่ไม่ใช่วิธีการใช้งานทั่วไปมันไม่สอดคล้องกับอนุสัญญาทั่วไป ไวยากรณ์ชนิดนี้มีข้อดีข้อเสียแน่นอน:

จุดด้อย

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

ข้อดี

  • สามารถอ่านได้มากขึ้นหลังจากผู้พัฒนาปรับเป็นไวยากรณ์นี้

บรรทัดล่าง - ในการออกแบบ API สาธารณะฉันจะเลือกวิธีที่ชัดเจนกว่านี้


2
@Elisha - ข้อดีข้อเสียของคุณจะถูกย้อนกลับ อย่างน้อยฉันหวังว่าคุณจะไม่บอกว่าโปรกำลังมีรหัส "ไม่เข้าใจ" ;-)
Metro Smurf

สำหรับกรณีนี้ - ชื่อพารามิเตอร์แลมบ์ดาและพารามิเตอร์สตริงนั้นทั้งสองมีความเปราะบาง มันเหมือนกับการใช้ไดนามิกสำหรับการแยกวิเคราะห์ xml - มันเหมาะสมเพราะคุณไม่แน่ใจเกี่ยวกับ xml อยู่ดี
Arnis Lapsa

19

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

แทนที่จะจัดหาแอตทริบิวต์โดยใช้อาร์เรย์ของผู้รับมอบสิทธิ์วิธีการผูกมัดจะชัดเจนและทำงานได้ดีขึ้น:

.Attribute("style", "width:100%;").Attribute("class", "test")

แม้ว่านี่จะเป็นแบบอื่น ๆ อีกเล็กน้อย แต่ก็ชัดเจนและใช้งานง่าย


6
จริงๆ? ฉันรู้อย่างชัดเจนว่าโค้ดขนาดไหนที่ตั้งใจเมื่อฉันดู ไม่ใช่ป้านนั้นเว้นแต่คุณจะเข้มงวดมาก ใคร ๆ ก็สามารถให้เหตุผลเดียวกันเกี่ยวกับการบรรทุกเกินพิกัด + สำหรับการเรียงสตริงได้และเราควรใช้เมธอด Concat () แทน
Samantha Branham

4
@ Stuart: ไม่คุณไม่ทราบแน่ชัดคุณแค่เดาตามค่าที่ใช้ ทุกคนสามารถเดาได้ แต่การเดาไม่ใช่วิธีทำความเข้าใจโค้ดที่ดี
Guffa

11
ฉันเดาว่าการใช้.Attribute("style", "width:100%")ให้ฉันstyle="width:100%"แต่สำหรับทุกอย่างที่ฉันรู้ก็สามารถให้ฉันfooooooได้ ฉันไม่เห็นความแตกต่าง
Samantha Branham

5
"การคาดเดาจากค่าที่ใช้" เป็นสิ่งที่คุณทำเมื่อดูโค้ดเสมอ หากคุณพบกับสายเรียกเข้าให้ปิด () คุณคิดว่ามันปิดกระแส แต่ก็อาจทำสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง
Wouter Lievens

1
@Wouter: หากคุณคาดเดาอยู่เสมอเมื่ออ่านรหัสคุณต้องมีปัญหาในการอ่านรหัส ... ถ้าฉันเห็นการเรียกไปยังวิธีการที่ชื่อว่า "ปิด" ฉันสามารถรวบรวมได้ว่าผู้เขียนชั้นเรียนไม่ทราบวิธีการตั้งชื่อ ดังนั้นฉันจะลังเลที่จะทำทุกอย่างเพื่อให้ได้สิ่งที่วิธีการทำ
Guffa

17

ฉันสามารถใช้สิ่งนี้เพื่อเหรียญวลี?

magic lambda (n): ฟังก์ชั่นแลมบ์ดาใช้เพื่อจุดประสงค์ในการเปลี่ยนสายเวทเท่านั้น


ใช่ ... มันตลกดี และบางทีมันก็เป็นเวทย์มนตร์ในแง่ของความปลอดภัยไม่มีเวลารวบรวมมีสถานที่ที่การใช้งานนี้จะทำให้เกิดรันไทม์แทนข้อผิดพลาดในการรวบรวมเวลา?
Maslow


16

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

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

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

แก้ไข: ฉันได้กล่าวว่า "กุญแจสำคัญในการทำให้ซอฟต์แวร์บำรุงรักษาได้มากขึ้นและแม่นยำยิ่งขึ้น" ซึ่งเป็นบิตที่ไร้เดียงสาอย่างไร้เดียงสาที่พูดเกินจริง ฉันเปลี่ยนเป็น "กุญแจ"


12

นี่คือหนึ่งในประโยชน์ของต้นไม้นิพจน์ - หนึ่งสามารถตรวจสอบรหัสของตัวเองสำหรับข้อมูลเพิ่มเติม นั่นคือวิธีที่.Where(e => e.Name == "Jamie")สามารถแปลงเป็น SQL เทียบเท่าได้ที่ไหน นี่เป็นการใช้ต้นไม้แสดงออกอย่างชาญฉลาด แต่ฉันหวังว่ามันจะไม่ไปไกลกว่านี้อีก สิ่งที่ซับซ้อนกว่านั้นมีแนวโน้มว่าจะยากกว่าโค้ดที่หวังจะเปลี่ยนดังนั้นฉันสงสัยว่ามันจะเป็นการ จำกัด ตัวเอง


เป็นจุดที่ถูกต้อง แต่ความจริงในการโฆษณา: LINQ มาพร้อมกับชุดคุณลักษณะทั้งหมดเช่น TableAttribute และ ColumnAttribute ที่ทำให้เรื่องนี้เป็นเรื่องที่ถูกกฎหมายมากขึ้น การแมป linq ยังดูที่ชื่อคลาสและชื่อคุณสมบัติซึ่งมีความเสถียรมากกว่าชื่อพารามิเตอร์
Remus Rusanu

ฉันเห็นด้วยกับคุณที่นั่น ฉันได้เปลี่ยนจุดยืนของฉันในเรื่องนี้เล็กน้อยหลังจากอ่านสิ่งที่ Eric Lippert / Anders Helsberg / etc ต้องพูดในเรื่องนี้ คิดว่าฉันจะทิ้งคำตอบนี้ไว้เพราะยังมีประโยชน์บ้าง สำหรับสิ่งที่คุ้มค่าตอนนี้ฉันคิดว่ารูปแบบการทำงานกับ HTML นี้ดี แต่ก็ไม่เหมาะกับภาษา
Jamie Penney

7

มันเป็นวิธีการที่น่าสนใจ หากคุณ จำกัด ทางด้านขวาของนิพจน์ให้เป็นค่าคงที่เท่านั้นคุณสามารถนำไปใช้งานได้

Expression<Func<object, string>>

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

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

สิ่งนี้อาจแก้ปัญหาการเชื่อมโยงข้ามภาษาที่กล่าวถึงก่อนหน้าในเธรด


6

รหัสนั้นฉลาดมาก แต่อาจทำให้เกิดปัญหามากขึ้นในการแก้ไข

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

ทางออกที่ดีกว่าคือการมีสมาชิกข้อมูลที่สามารถตรวจสอบได้ในเวลารวบรวม ดังนั้นแทนที่จะเป็นเช่นนี้:

.Attributes(style => "width:100%");

โค้ดที่มีคุณสมบัติ Style สามารถตรวจสอบได้โดยคอมไพเลอร์:

.Attributes.Style = "width:100%";

หรือแม้กระทั่ง:

.Attributes.Style.Width.Percent = 100;

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


3
ฉันชื่นชมการตรวจสอบเวลาแบบคอมไพล์ แต่ฉันคิดว่านี่เป็นเรื่องของความคิดเห็น อาจเป็นเหมือนแอตทริบิวต์ใหม่ () {สไตล์: "ความกว้าง: 100%"} อาจชนะผู้คนมากกว่านี้เนื่องจากมีความกระชับมากกว่า การใช้ทุกอย่างที่ HTML อนุญาตนั้นเป็นงานที่ใหญ่มากและฉันไม่สามารถตำหนิใครได้แค่ใช้สาย / lambdas / คลาสที่ไม่ระบุตัวตน
Samantha Branham

5

แน่นอนมันดูเหมือน Ruby =) อย่างน้อยสำหรับฉันการใช้ทรัพยากรแบบคงที่สำหรับ "การค้นหา" แบบไดนามิกในภายหลังไม่เหมาะสำหรับการพิจารณาการออกแบบ api หวังว่าเคล็ดลับที่ฉลาดนี้เป็นทางเลือกใน api นั้น

เราสามารถสืบทอดจาก IDictionary (หรือไม่) และจัดทำดรรชนีที่ทำหน้าที่เหมือนอาเรย์ของ php เมื่อคุณไม่ต้องการเพิ่มคีย์เพื่อตั้งค่า มันจะเป็นการใช้งานที่ถูกต้องของ. net semantics ไม่ใช่แค่ c # และยังต้องการเอกสารประกอบ

หวังว่านี่จะช่วยได้


4

ในความคิดของฉันมันเป็นการละเมิดของ lambdas

ในฐานะที่เป็นความสามารถด้านไวยากรณ์ฉันพบstyle=>"width:100%"ความสับสนธรรมดา โดยเฉพาะอย่างยิ่งเพราะ=>แทนที่จะเป็น=


4

IMHO มันเป็นวิธีที่ยอดเยี่ยมในการทำ เราทุกคนชอบความจริงที่ว่าการตั้งชื่อตัวควบคุมคลาสจะทำให้มันเป็นตัวควบคุมใน MVC ใช่มั้ย ดังนั้นจึงมีหลายกรณีที่การตั้งชื่อไม่สำคัญ

นอกจากนี้ความตั้งใจชัดเจนมากที่นี่ มันง่ายมากที่จะเข้าใจว่า.Attribute( book => "something")จะส่งผลbook="something"และ.Attribute( log => "something")จะส่งผลให้log="something"

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


4
การตั้งชื่อชั้นตัวควบคุมจะไม่ทำหมอบ แต่ถ้าคุณไม่ได้รับมรดกจากตัวควบคุมเกินไป ...
จอร์แดน Wallwork

3

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


1

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

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