มีระเบียบการตั้งชื่อที่ชัดเจนสำหรับวิธีการส่งคืน IAsyncEnumerable หรือไม่


10

หลังจาก C # 5 แนะนำasyncและawaitโมเดลสำหรับการโปรแกรมแบบอะซิงโครนัสชุมชน C # มาถึงการประชุมการตั้งชื่อเพื่อเพิ่มคำต่อท้าย "Async" ลงในเมธอดที่ส่งคืนชนิดที่ไม่ต้องรอคอยเช่นนี้

interface Foo
{
   Task BarAsync();
}

เครื่องวิเคราะห์รหัสแบบสแตติกจำนวนมาก (ทั้งที่ใช้แบบ Roslyn และแบบที่ไม่ใช่แบบ Roslyn) ได้ถูกเขียนขึ้นอยู่กับแบบแผนการตั้งชื่อนี้เมื่อตรวจจับกลิ่นรหัสรอบโปรแกรมแบบอะซิงโครนัส

ตอนนี้ C # 8 ได้นำเสนอแนวคิดของการแจกแจงแบบอะซิงโครนัสซึ่งตัวเองไม่สามารถรอได้ แต่สามารถใช้ร่วมกับawait foreachดูเหมือนว่ามีสองตัวเลือกสำหรับวิธีการตั้งชื่อที่ส่งคืนIAsyncEnumerable:

interface Foo
{
    // No "Async" suffix, indicating that the return value is not awaitable.
    IAsyncEnumerable<T> Bar<T>();
}

หรือ

interface Foo
{
    // With "Async" suffix, indicating that the overall logic is asynchronous.
    IAsyncEnumerable<T> BarAsync<T>();
}

มีแนวทางการตั้งชื่อที่ชัดเจน (จากทีมภาษา C #,. NET Foundation หรือหน่วยงานอื่น ๆ ) เกี่ยวกับตัวเลือกข้างต้นเช่นวิธีการตั้งชื่อการประชุม C # 5 เป็นมาตรฐานที่ชัดเจนและไม่ถูกตัดสินตามความเห็นของโปรแกรมเมอร์?


2
ตัวเลือกที่ 2 ฟังดูถูกต้องที่นี่เนื่องจากคุณเรียกใช้รหัสนี้แบบอะซิงโครนัส (ทำเครื่องหมายวิธีเป็นasyncและใช้awaitภายใน) และตัวอย่าง
msdn

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

.NET คอตัวเองใช้Asyncคำต่อท้ายสำหรับวิธีการที่ส่งกลับIAsyncEnumerableเช่นChannelReader.ReadAllAsync ในกรณีอื่น ๆ เช่นใน EF Core AsAsyncEnumerable()ถูกใช้ซึ่งชัดเจนอยู่แล้ว
Panagiotis Kanavos

มีหลักเกณฑ์การตั้งชื่อเพื่อให้มนุษย์เข้าใจรหัสได้ง่ายขึ้น หากจุดประสงค์ของรหัสไม่ชัดเจนให้เพิ่มคำต่อท้าย
Panagiotis Kanavos

คำตอบ:


1

ไม่มีแนวทางที่ดีไปกว่าสิ่งที่ทีมงาน. NET ทำอยู่แล้ว :

  • ChannelReader.ReadAllAsyncส่งกลับค่าIAsyncEnumerable<T>
  • ใน EF Core 3 ผลลัพธ์จะถูกส่งคืนIAsyncEnumerableโดยการเรียกAsAsyncEnumerable ()
  • ใน System.Linq.Async, ToAsyncEnumerable ()จะแปลง IEnumerables, Tasks และ Observables ให้เป็นIAsyncEnumerables
  • ผู้ประกอบการอื่น ๆ ทั้งหมดในการSystem.Linq.Asyncรักษาชื่อของพวกเขา ไม่มีSelectAsyncหรือเพียงSelectAsAsyncEnumerableSelect

ในทุกกรณีมันชัดเจนว่าผลลัพธ์ของวิธีการคืออะไร ในทุกกรณีผลลัพธ์ของวิธีการนั้นต้องรอawait foreachก่อนจึงจะสามารถใช้งานได้

ดังนั้นแนวทางที่แท้จริงยังคงเหมือนเดิม - ให้แน่ใจว่าชื่อทำให้พฤติกรรมชัดเจน :

  • เมื่อชื่อชัดเจนแล้วเช่นกับAsAsyncEnumerable()หรือToAsyncEnumerable()ไม่จำเป็นต้องเพิ่มคำต่อท้ายใด ๆ
  • ในกรณีอื่น ๆ ให้เพิ่มAsyncคำต่อท้ายเพื่อให้นักพัฒนาทราบว่าพวกเขาต้องการawait foreachผลลัพธ์

เครื่องวิเคราะห์รหัสและเครื่องกำเนิดไฟฟ้าไม่สนใจชื่อวิธีการตรวจจับกลิ่นโดยการตรวจสอบรหัสเอง วิเคราะห์รหัสจะบอกคุณว่าคุณลืมที่จะรองานหรือไม่ว่าคุณจะเรียกวิธีการและตัวแปร เครื่องกำเนิดไฟฟ้าสามารถใช้การสะท้อนเพื่อตรวจสอบและปล่อยawait foreachIAsyncEnumerableIAsyncEnumerableawait foreach

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

และแน่นอนว่าทุกคนรู้ว่าคำนำหน้าทั่วไปสำหรับเขตข้อมูลอินสแตนซ์ส่วนตัวคือ_:)


ขอบคุณสำหรับการชี้ChannelReader.ReadAllAsyncตัวอย่าง เนื่องจากสิ่งนี้มาจากทีม. NET จึงเป็นเรื่องยากที่จะทำตามคำแนะนำต่อไปนี้
hwaien

แพ็คเกจวิเคราะห์มักมาพร้อมกับถุงที่มีสไตล์และตัววิเคราะห์ที่ไม่ใช่แบบ ตัวอย่างเช่นแพ็คเกจMicrosoft.VisualStudio.Threading.Analyzersมีตัววิเคราะห์ลักษณะที่ตรวจสอบแบบแผนการตั้งชื่อ (VSTHRD200) และตัววิเคราะห์ที่ไม่ใช่ลักษณะที่ตรวจจับสถานการณ์อันตรายที่อาจนำไปสู่การหยุดชะงัก (VSTHRD111) ในการอ้างอิงแพ็คเกจเพื่อใช้ประโยชน์จาก VSTHRD111 โครงการก็จะจบลงด้วย VSTHRD200
hwaien

2

ไม่ใช่วิธี async ดังนั้นชื่อไม่ควรลงท้ายด้วย 'Async' ส่วนต่อท้ายของวิธีนั้นเป็นแบบแผนเพื่อให้ชัดเจนว่าควรรอวิธีหรือผลลัพธ์ที่จัดการเป็นงาน

ฉันคิดว่าชื่อที่ส่งคืนตามปกติมีความเหมาะสม GetFoos () หรือคล้ายกัน


ทั้งหมดเหล่านี้เป็นข้อโต้แย้งสำหรับการใช้Asyncคำต่อท้าย ส่วนต่อท้ายที่ใช้ใน. NET Core นั้น: ChannelReader.ReadAllAsyncส่งคืน IAsyncEnumerable IAsyncEnumerableจะต้องมีการใช้กับawait foreachดังนั้นคำต่อท้ายจะทำให้ความรู้สึก
Panagiotis Kanavos

1

Asyncต่อท้ายและแม้กระทั่งคำหลักasyncเป็นเพียงสำเร็จรูปมันไม่มีความหมายนอกเหนือจากข้อโต้แย้งความเข้ากันได้ย้อนหลังบางอย่าง C # มีข้อมูลทั้งหมดเพื่อแยกฟังก์ชั่นเหล่านั้นเช่นเดียวกับที่แตกต่างกันyieldในวิธีการที่กลับมาIEnumerableเพราะคุณรู้ว่าคุณไม่จำเป็นต้องเพิ่มอะไรเช่นenumerableหรือคำหลักอื่น ๆ ในวิธีการดังกล่าว

คุณต้องเพิ่มคำต่อท้ายAsyncเพียงเพราะ C # จะบ่นเกี่ยวกับการโอเวอร์โหลดดังนั้นโดยพื้นฐานแล้วทั้งสองนั้นเหมือนกันและพวกเขาทำสิ่งเดียวกันโดยกฎทั้งหมดของความแตกต่าง

public interface IMyContract
{
    Task<int> Add(int a, int b);
    int Add(int a, int b);
}

แต่คุณเขียนมันไม่ได้เพราะคอมไพเลอร์จะบ่น แต่เดี๋ยวก่อน! มันจะกลืนสิ่งประหลาดนี้

public interface IMyContract : IEnumerable<int>, IEnumerable<long>
{
}

และแม้กระทั่งสิ่งนี้:

public interface IMyContractAsync
{
    Task<int> Add(int a, int b);
}

public interface IMyContract : IMyContractAsync
{
    int Add(int a, int b);
}

ดังนั้นนี่คือมัน คุณเพิ่มAsyncเพียงเพื่อหยุดคอมไพเลอร์ให้บ่น ไม่ต้องอธิบายให้ชัดเจน ไม่ทำให้ดีขึ้น ถ้าไม่มีบ่น - Task<IAsyncEnumerable>ไม่มีเหตุผลที่จะเพิ่มมันดังนั้นในกรณีของคุณผมจะหลีกเลี่ยงปัญหานี้เว้นแต่มันจะกลายเป็น

PS:เพียงแค่ดีขึ้นของการทำความเข้าใจของภาพทั้งหมดที่นี่ - ถ้าบางครั้งในคนเพิ่มในอนาคตใน C นามสกุลวิธี # ควอนตัมคอมพิวเตอร์ (fantazy ฮะ) ซึ่งจะดำเนินการในกระบวนทัศน์ที่แตกต่างกันเราอาจจะต้องต่อท้ายอีกเช่นควอนท์หรืออะไรเพราะ C # จะบ่นเป็นอย่างอื่น มันจะเป็นวิธีการเดียวกันแน่นอน แต่มันจะทำงานอีกวิธีหนึ่ง เช่นเดียวกับความหลากหลายที่ทำ เหมือนอินเทอร์เฟซทำ


1
ขออภัย แต่ฉันรู้สึกว่าฉันไม่เห็นด้วยมันไม่ใช่วิธีการที่แตกต่างกันในการทำสิ่งเดียวกัน - มันมีมากกว่า - คาดว่าจะถูกเรียกแตกต่างกันและผลลัพธ์จะถูกรวบรวมแตกต่างกัน นั่นคือข้อแตกต่างระหว่าง async และ non-async ฉันเชื่ออย่างยิ่งว่าการเพิ่ม async นั้นมีไว้เพื่อความชัดเจน ฉันคิดว่านี่เป็นคำแนะนำของ Microsoft เช่นกัน
madoxdev

ใช่ฉันเห็นด้วย แต่ไม่เห็นด้วย เช่นเดียวกับในรายการคุณมีฟังก์ชั่นการเรียงอย่างง่ายและไม่ใช่ "QuickSort", "RadixSort", "BubbleSort", "MixOfSorts" มีความแตกต่างใช้ตามขอบเขต แต่เห็นได้ชัดว่าไม่ต้องการความกระจ่างนอกเหนือจากจุดประสงค์ในการดีบั๊ก (ฉันหมายถึงคุณใส่ใจพวกเขาเฉพาะเมื่อมันส่งผลกระทบต่อประสิทธิภาพการทำงาน / ทรัพยากร) ในกรณีนี้ DoThing และ DoThingAsync อยู่ในสถานการณ์เดียวกันกับอัลกอริทึม templated อื่น ๆ พวกเขาไม่ต้องการการชี้แจงมันได้รับการสนับสนุนหรือไม่และมีประโยชน์สำหรับการดีบักเท่านั้น
eocron

นั่นคือ async ที่แตกต่างกันหมายความว่า - heu caller ให้แน่ใจว่าคุณจัดการอย่างนี้ ข้อเท็จจริงของการถอนงานไม่เพียงพอที่จะบอกว่าวิธีการนี้เป็น Async อย่างแท้จริง ผู้โทรต้องรู้ว่าจะรอหรือใช้ GetAwaiter () GetResilt () เพื่อรับ oitput เดียวกัน มันแตกต่างกันไม่ใช่วิธีการทำสิ่งต่าง ๆ ภายใน
madoxdev

นี่คือจุดประสงค์ทั้งหมดของตัววิเคราะห์รหัสและตัวรวบรวม IntellySense สามารถชี้สิ่งนี้ให้กับคุณได้อย่างง่ายดายโดยไม่จำเป็นต้องใช้สมองของนักพัฒนาซอฟต์แวร์เพื่อเน้นหรือแม้แต่ห้ามใช้วิธีการซิงค์ผ่าน async หนึ่งในรหัสอะซิงโครนัส จากประสบการณ์ของฉันเมื่อใช้ Async ฉัน rarelly จำเป็นต้องใช้ GetResult () แต่บ่อยครั้งฉันจำเป็นต้องทำให้รหัสฐานทั้งหมดสกปรกด้วย Async
eocron

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