Việc sử dụng hậu tố “Async” trong tên phương thức có phụ thuộc vào việc liệu công cụ sửa đổi 'async' có được sử dụng không?


106

Quy ước cho các tên phương thức hậu tố với "Async" là gì?

Có nên thêm hậu tố "Async" chỉ vào một phương thức được khai báo với công cụ asyncsửa đổi không?

public async Task<bool> ConnectAsync()

Hoặc là nó đủ để phương thức chỉ trả về Task<T>hoặc Task?

public Task<bool> ConnectAsync()

4
Đối với phần đặt tên, tài liệu TAP cho biết: Các phương thức không đồng bộ trong TAP bao gồm hậu tố Async sau tên hoạt động; ví dụ: GetAsync cho hoạt động get. Nếu bạn đang thêm phương thức TAP vào một lớp đã chứa tên phương thức đó với hậu tố Async, hãy sử dụng hậu tố TaskAsync để thay thế. Ví dụ: nếu lớp đã có phương thức GetAsync, hãy sử dụng tên GetTaskAsync.
James Manning

4
ok, tôi đoán tôi đã nhầm lẫn bởi tiêu đề câu hỏi của "quy ước đặt tên cho các phương pháp async"
James Manning

1
Đây là một câu hỏi được xây dựng kém. Mọi người cãi nhau, câu trả lời thiếu cân nhắc.
Luke Puplett,

4
Bởi vì nhiều người đã hiểu sai nó và đang tranh cãi về điều thực tế đang được hỏi, tự hỏi liệu nó có phải là một câu hỏi gồm hai phần hay không, v.v. Bằng chứng cho thấy sự khó hiểu của nó là mọi người đang bối rối.
Luke Puplett,

2
@DavidRR Cho đến ngày nay, tôi vẫn không hiểu mức độ nhầm lẫn mà câu hỏi này dường như đã gây ra. Nếu các chỉnh sửa của bạn mang lại một số thứ tự trong sự nhầm lẫn như nó đã giúp bạn và có thể có thể giúp người khác, thì tôi hoan nghênh các chỉnh sửa của bạn vì bạn đã đạt được điều gì đó mà tôi không thể trong công thức ban đầu. Câu hỏi giờ đã cũ đến mức tôi khó có thể nhớ lại suy nghĩ của mình khi hỏi nó ở đây và vì vậy mục đích ban đầu ít quan trọng hơn. Câu trả lời của Luke phản ánh rằng không phải tất cả đều bối rối. Tôi thấy nó vô cùng hữu ích.
kasperhj

Câu trả lời:


127

Tôi nghĩ rằng sự thật còn mơ hồ ngay cả từ tài liệu của Microsoft:

Trong Visual Studio 2012 và .NET Framework 4.5, bất kỳ phương thức nào được gán với asynctừ khóa ( Asynctrong Visual Basic) được coi là phương thức không đồng bộ và trình biên dịch C # và Visual Basic thực hiện các biến đổi cần thiết để triển khai phương thức không đồng bộ bằng cách sử dụng TAP. Một phương thức không đồng bộ sẽ trả về một Taskhoặc một Task<TResult>đối tượng.

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

Điều đó không đúng rồi. Bất kỳ phương pháp với asynclà không đồng bộ và sau đó nó nói rằng nó phải trả lại hoặc là một Taskhay Task<T>- mà không phải là phù hợp với phương pháp ở trên cùng của một cuộc gọi stack, Button_Click ví dụ, hoặc async void.

Tất nhiên, bạn phải xem xét điểm của quy ước là gì?

Bạn có thể nói rằng Asyncquy ước hậu tố là để thông báo với người dùng API rằng phương thức này có thể chờ được. Đối với một phương thức có thể chờ đợi được, nó phải trả về giá trị Tasktrống hoặc Task<T>đối với phương thức trả về giá trị, có nghĩa là chỉ phương thức sau mới có thể được gắn với Async.

Hoặc bạn có thể nói rằng Asyncquy ước hậu tố là để thông báo rằng phương thức có thể trả về ngay lập tức, từ bỏ luồng hiện tại để thực hiện công việc khác và có khả năng gây ra các cuộc đua.

Trích dẫn tài liệu của Microsoft này cho biết:

Theo quy ước, bạn thêm "Async" vào tên của các phương thức có công cụ sửa đổi Async hoặc async.

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

Điều này thậm chí còn không đề cập đến việc các phương thức không đồng bộ của riêng bạn trả về Taskcần Asynchậu tố, điều mà tôi nghĩ tất cả chúng ta đều đồng ý.


Vì vậy, câu trả lời cho câu hỏi này có thể là: cả hai. Trong cả hai trường hợp, bạn cần thêm Asynccác phương thức có asynctừ khóa và trả về Taskhoặc Task<T>.


Tôi sẽ hỏi Stephen Toub để làm rõ tình hình.

Cập nhật

Tôi cũng vậy. Và đây là những gì người đàn ông tốt của chúng ta đã viết:

Nếu một phương thức công khai là trả về Tác vụ và có bản chất là không đồng bộ (trái ngược với một phương thức được biết là luôn thực thi đồng bộ cho đến khi hoàn thành nhưng vẫn trả về một Tác vụ vì lý do nào đó), thì nó phải có hậu tố “Không đồng bộ”. Đó là kim chỉ nam. Mục tiêu chính ở đây với việc đặt tên là làm cho người tiêu dùng hiểu rõ về chức năng rằng phương thức được gọi có thể sẽ không hoàn thành đồng bộ tất cả công việc của nó; tất nhiên nó cũng hữu ích trong trường hợp chức năng được hiển thị với cả phương thức đồng bộ và không đồng bộ, do đó bạn cần sự khác biệt về tên để phân biệt chúng. Cách phương thức đạt được sự triển khai không đồng bộ của nó là không quan trọng đối với việc đặt tên: liệu async / await được sử dụng để thu hút sự trợ giúp của trình biên dịch hay liệu các kiểu và phương thức từ System.Threading.Tasks được sử dụng trực tiếp (e. g. TaskCompletionSource) không thực sự quan trọng, vì điều đó không ảnh hưởng đến chữ ký của phương pháp đối với người tiêu dùng phương thức.

Tất nhiên, luôn có những ngoại lệ đối với một hướng dẫn. Điều đáng chú ý nhất trong trường hợp đặt tên sẽ là các trường hợp mà nguyên tắc đặc biệt của toàn bộ loại là cung cấp chức năng tập trung vào không đồng bộ, trong trường hợp này có Không đồng bộ trên mọi phương thức sẽ là quá mức cần thiết, ví dụ như các phương thức trên chính Tác vụ tạo ra các Tác vụ khác .

Đối với các phương thức không đồng bộ trả về void-return, không mong muốn có các phương thức đó trong khu vực bề mặt công khai, vì người gọi không có cách nào tốt để biết khi nào công việc không đồng bộ đã hoàn thành. Tuy nhiên, nếu bạn phải công khai một phương thức không đồng bộ trả về void trả về công khai, bạn có thể muốn có một tên truyền tải rằng công việc không đồng bộ đang được bắt đầu và bạn có thể sử dụng hậu tố “Async” ở đây nếu nó hợp lý. Vì trường hợp này hiếm khi xảy ra, tôi cho rằng đó thực sự là một loại quyết định theo từng trường hợp.

Tôi hy vọng điều đó sẽ giúp, Steve

Lời dẫn ngắn gọn từ câu mở đầu của Stephen đủ rõ ràng. Nó loại trừ async voidvì việc muốn tạo một API công khai với thiết kế như vậy là không bình thường vì cách chính xác để triển khai khoảng trống không đồng bộ là trả về một thể hiện đơn giản Taskvà để trình biên dịch hoạt động hiệu quả. Tuy nhiên, nếu bạn muốn một public async void, thì Asyncnên bổ sung. Các async voidphương thức top-of-stack khác như trình xử lý sự kiện thường không công khai và không quan trọng / đủ điều kiện.

Đối với tôi, nó cho tôi biết rằng nếu tôi thấy mình băn khoăn về việc thêm hậu tố Asyncvào một async void, có lẽ tôi nên chuyển nó thành một async Taskđể người gọi có thể chờ đợi nó, sau đó thêm vào Async.


20
Thật tiếc là chúng tôi không có kiểm tra thời gian biên dịch cho các cuộc gọi phương thức .. ồ chờ đã. Nếu tôi đặt tên Phương thức Get hoặc GetAsync và không sử dụng chờ đợi từ phía gọi, trình biên dịch sẽ không thể xây dựng. Vì vậy, quy ước này là SILLY và thực sự đi ngược lại nhiều nguyên tắc Phong cách của Microsoft, như tránh những thứ tương tự PersonStringhoặc PriceDecimalvì vậy tại sao phải sử dụng GetAsync- người tiêu dùng API của API không đồng bộ không cần phải lo lắng về điều này vì dù sao thì yêu cầu luôn trả về sau khi mọi tác vụ hoàn thành. Nó ngớ ngẩn và thực sự làm tôi khó chịu. Nhưng nó chỉ là một quy ước khác mà không ai thực sự biết tại sao nó ở đó.
Piotr Kula

2
@ppumkin: Như Stephen đã chỉ ra, một phương thức có thể dễ dàng không đồng bộ về bản chất mà không cần sử dụng async / await, do đó người gọi không có bất kỳ dấu hiệu nào ngoài tên cho dù chức năng có chạy không đồng bộ hay không.
Hannobo

6
@ppumkin: Theo mặc định, không chờ được phương thức không đồng bộ, dẫn đến cảnh báo thời gian biên dịch; không phải lỗi xây dựng.
Dustin Cleveland

7
Tôi thấy quy ước này ngớ ngẩn. Có ba dấu hiệu tự động cho thấy một phương thức không đồng bộ: 1. Kiểu trả về là Tác vụ. 2. Việc hoàn thành mã đưa ra một gợi ý có thể chờ đợi 3. IDE sẽ cảnh báo bạn bằng cách gạch chân màu xanh lá cây và đưa ra cảnh báo trình biên dịch. Vì vậy, tôi hoàn toàn đồng ý với @ppumkin. Hậu tố Async thật ngớ ngẩn như thể bạn đã viết một thuộc tính như vậy: public Lazy <Customer> CustomerLazy. Ai sẽ làm điều này! ??
Marco

2
@Marco Tôi đã nêu ra ý tưởng này trên GitHub, nghĩ rằng đó là nơi tốt nhất, nhưng không có sự tương tác với nó, tôi nghĩ mình sẽ nhận được: github.com/dotnet/core/issues/1464
Luke Puplett,

68

Tôi xây dựng nhiều dịch vụ API và các ứng dụng khác gọi những hệ thống khác mà hầu hết mã của tôi đang chạy không đồng bộ.

Quy tắc ngón tay cái của riêng tôi mà tôi đang tuân theo là:

Nếu có cả phương thức không đồng bộ và không đồng bộ trả về cùng một thứ, tôi đặt hậu tố là phương thức không đồng bộ với Async. Nếu không thì không.

Ví dụ:

Chỉ một phương pháp:

public async Task<User> GetUser() { [...] }

Phương pháp tương tự với hai chữ ký:

public User GetUser() { [...] }

public async Task<User> GetUserAsync() { [...] }

Điều này có ý nghĩa vì cùng một dữ liệu được trả về nhưng điều duy nhất khác biệt là cách trả về dữ liệu , không phải bản thân dữ liệu.

Tôi cũng nghĩ rằng quy ước đặt tên này tồn tại do sự cần thiết phải giới thiệu các phương thức không đồng bộ và vẫn duy trì khả năng tương thích ngược.

Tôi cho rằng mã mới không nên sử dụng hậu tố Async. Nó cũng hiển nhiên như kiểu trả về của Chuỗi hoặc Int như đã đề cập trước đó trong chủ đề này.


8
); - Tôi đồng ý, đặc biệt là thông thường bạn cần phải đi 'async tất cả các cách', trong trường hợp này là không cần thiết suffix điểm của phụ nó đến 90% của mã này là gì
Bartosz

3
đây là giải pháp tốt nhất. Không nhận ra nó, tôi đã làm theo cách tương tự trong các API của mình.
Marco

2
Đây là cách tốt hơn so với suffixing wiht "Async" tất cả các phương pháp ứng dụng async
Mariusz Jamro

Vấn đề với kỹ thuật này là nếu bạn tạo phiên bản không đồng bộ sau này, bạn không thể sử dụng tên "GetUser ()" ưa thích của mình.
David,

3
Đây là cách thực dụng để đi. Việc thêm Async vào mọi phương thức có công cụ sửa đổi async chỉ là Hungarian Notation 2019. @David nếu bạn kết thúc thêm phiên bản không phải async sau đó, thì hãy đổi tên các phương thức và tuân theo quy ước đặt tên hoặc đừng làm điều đó.
Skrymsli

25

Quy ước cho tên phương thức hậu tố với "Async" là gì.

Các công tác dựa trên mẫu không đồng bộ (TAP) mệnh lệnh rằng phương pháp này cần luôn luôn trả về một Task<T>(hoặc Task) và được đặt tên với một Async hậu tố; điều này tách biệt với việc sử dụng async. Cả hai Task<bool> Connect()và sẽ biên dịch và chạy tốt, nhưng bạn sẽ không tuân theo quy ước đặt tên TAP.asyncTask<bool> Connect()

Phương thức có nên chứa công cụ asyncsửa đổi hay đủ để nó chỉ trả về Tác vụ?

Nếu phần thân của phương thức (bất kể kiểu trả về hoặc tên) bao gồm await, bạn phải sử dụng async; và trình biên dịch sẽ cho bạn biết "Toán tử 'await' chỉ có thể được sử dụng trong một phương thức không đồng bộ. ...". Trả lại Task<T>hoặc Taskkhông đủ "" để tránh sử dụng async. Xem async (C # Reference) để biết chi tiết.

Tức là chữ ký nào trong số những chữ ký này là đúng:

Cả hai asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()tuân thủ đúng các quy ước TAP. Bạn luôn có thể sử dụng asynctừ khóa, nhưng bạn sẽ nhận được cảnh báo trình biên dịch "Phương thức không đồng bộ này thiếu các toán tử 'await' và sẽ chạy đồng bộ. ..." nếu phần thân không sử dụng await.


1
Anh ấy đang đề cập đến việc bạn có thêm "Không đồng bộ" vào tên phương thức hay không, chứ không phải việc bạn có sử dụng asynctừ khóa hay không.
Servy

1
@Servy wether hay không sử dụng từ khóa asynclà phần thứ hai của câu hỏi.
Corak

2
@Servy Đây là một câu hỏi gồm hai phần. Phần đầu tiên, như bạn đã nói là có nên thêm "Async" vào tên phương thức hay không. Phần thứ hai là có hay không sử dụng asyncbổ ngữ. Xem thêm các ví dụ về OP, public async Task<bool> ConnectAsync()(có asyncbổ trợ) so với public Task<bool> ConnectAsync()(không asyncbổ trợ). Bản thân tên phương thức có hậu tố "Async" trong cả hai trường hợp.
Corak

2
không phải là một câu hỏi hai phần. Câu hỏi là, "Async" có nên được thêm vào tên các phương thức của các phương thức trả về Taskhoặc các phương thức có async Task.
kasperhj

3
@lejon: bạn nên cải thiện câu hỏi; "so với" các đoạn mã làm rõ câu hỏi (toàn bộ) là về sự không đồng bộ vì đó là sự khác biệt duy nhất.
Ðаn

11

hoặc đủ để nó chỉ trả về Tác vụ?

Cái đó. Các asynctừ khóa không phải là vấn đề thực sự ở đây. Nếu bạn triển khai phương thức không đồng bộ mà không sử dụng asynctừ khóa, phương pháp vẫn là "Không đồng bộ", theo nghĩa chung.


7

TaskTask<T>đều là các loại có thể chờ đợi, chúng đại diện cho một số hoạt động không đồng bộ. Hoặc ít nhất họ nên đại diện.

Bạn nên thêm hậu tố Asyncvào một phương thức, trong một số trường hợp (không nhất thiết là tất cả), không trả về giá trị mà trả về một trình bao bọc xung quanh một hoạt động đang diễn ra. Trình bao bọc đó thường là a Task, nhưng trên Windows RT thì có thể như vậy IAsyncInfo. Hãy theo dõi cảm giác của bạn và nhớ rằng nếu người dùng mã của bạn nhìn thấy Asynchàm, họ sẽ biết rằng lệnh gọi của phương thức đó được tách khỏi kết quả của phương thức đó và họ cần phải hành động theo đó.

Lưu ý rằng có những phương thức như Task.DelayTask.WhenAlltrả về Tasknhưng không có Asynchậu tố.

Cũng lưu ý rằng có những async voidphương thức đại diện cho phương thức không đồng bộ và quên phương thức không đồng bộ và bạn nên biết rằng phương thức được xây dựng theo cách đó.


6

Tôi sẽ tranh luận rằng nó nên sử dụng hậu tố Async nếu nó trả về một Tác vụ bất kể phương thức được khai báo với async sửa đổi hay không.

Lý do đằng sau đó là tên được khai báo trong giao diện. Giao diện khai báo kiểu trả về là a Task. Sau đó, có hai triển khai của giao diện đó, một triển khai thực hiện nó bằng cách sử dụng công cụ asyncsửa đổi, còn lại thì không.

public interface IFoo
{
    Task FooAsync();
}

public class FooA : IFoo
{
    public Task FooAsync() { /* ... */ }
}

public class FooB : IFoo
{
    public async Task FooAsync() { /* ... */ }
}

Đúng đấy. Chúng tôi luôn sử dụng giao diện, ở mọi nơi và không thể khai báo giao diện là không đồng bộ. Vì vậy, các hướng dẫn chính thức về cách sử dụng hậu tố Async dường như hoàn toàn vô nghĩa đối với tôi. Tôi nghĩ rằng từ khóa async chỉ là một chi tiết triển khai, một phần của nội dung của phương thức và không nên ảnh hưởng đến tên của nó hoặc bất kỳ thứ gì bên ngoài.
Al Kepp

5

Trong Lập trình không đồng bộ với không đồng bộ và chờ đợi (C #) , Microsoft đưa ra hướng dẫn sau:

Quy ước đặt tên

Theo quy ước, bạn nối thêm "Async" vào tên của phương pháp mà có một async modifier.

Bạn có thể bỏ qua quy ước trong đó một sự kiện, lớp cơ sở hoặc hợp đồng giao diện đề xuất một tên khác. Ví dụ: bạn không nên đổi tên các trình xử lý sự kiện phổ biến, chẳng hạn như Button1_Click.

Tôi thấy hướng dẫn này không đầy đủ và không hài lòng. Điều này có nghĩa là trong trường hợp không có công cụ asyncsửa đổi, phương thức này nên được đặt tên Connectthay vì ConnectAsync?

public Task<bool> ConnectAsync()
{
    return ConnectAsyncInternal();
}

Tôi không nghĩ vậy. Như đã chỉ ra trong câu trả lời ngắn gọn của @Servycâu trả lời chi tiết hơn của @Luke Puplett , tôi tin rằng nó phù hợp và thực sự mong đợi rằng phương thức này nên được đặt tên ConnectAsync(vì nó trả về một phương thức thể chờ được ). Để hỗ trợ thêm cho điều này, @John Skeet trong câu trả lời này cho câu hỏi khác sẽ gắn Asyncvào tên phương thức bất kể sự hiện diện của công cụ asyncsửa đổi.

Cuối cùng, về một câu hỏi khác , hãy xem xét nhận xét này của @Damien_The_Un Believer :

async/awaitlà chi tiết triển khai các phương pháp của bạn. Cho dù phương thức của bạn được khai báo async Task Method()hay chỉ là vấn đề không quan trọng Task Method(), cho đến khi người gọi của bạn quan tâm. (Trên thực tế, bạn có thể tự do thay đổi giữa hai điều này vào thời điểm sau đó mà không bị coi là thay đổi vi phạm.)

Từ đó, tôi suy ra rằng chính bản chất không đồng bộ của phương thức quyết định cách đặt tên cho nó. Người dùng của phương pháp thậm chí sẽ không biết liệu công cụ asyncsửa đổi có được sử dụng trong việc triển khai nó hay không (không có mã nguồn C # hoặc CIL).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.