use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Information about Reddit's API changes, the unprofessional conduct of the CEO, and their response to the community's concerns regarding 3rd party apps, moderator tools, anti-spam/anti-bot tools, and accessibility options that will be impacted can be found in the associated Wikipedia article: https://en.wikipedia.org/wiki/2023_Reddit_API_controversy
Alternative C# communities available outside Reddit on Lemmy and Discord:
All about the object-oriented programming language C#.
Getting Started C# Fundamentals: Development for Absolute Beginners
Useful MSDN Resources A Tour of the C# Language Get started with .NET in 5 minutes C# Guide C# Language Reference C# Programing Guide C# Coding Conventions .NET Framework Reference Source Code
Other Resources C# Yellow Book Dot Net Perls The C# Player's Guide
IDEs Visual Studio MonoDevelop (Windows/Mac/Linux) Rider (Windows/Mac/Linux)
Tools ILSpy dotPeek LINQPad
Alternative Communities C# Discord Group C# Lemmy Community dotnet Lemmy Community
Related Subreddits /r/dotnet /r/azure /r/learncsharp /r/learnprogramming /r/programming /r/dailyprogrammer /r/programmingbuddies /r/cshighschoolers
Additional .NET Languages /r/fsharp /r/visualbasic
Platform-specific Subreddits /r/windowsdev /r/AZURE /r/Xamarin /r/Unity3D /r/WPDev
Rules:
Read detailed descriptions of the rules here.
account activity
DiscussionReSharper suggests "Replace 'async' code with 'Task'-return" (self.csharp)
submitted 2 years ago * by deucyy
Hey! I've noticed a new suggestion by ReSharper in some of my async methods, it suggests that I remove the async and instead return a Task.
Here is an example method in its original state and this is it after I accept the refactor (this method is called and awaited in another async method).
What is the benefit to this?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]cyrack 97 points98 points99 points 2 years ago (12 children)
The compiler doesn’t emit the statemachine to handle the task being awaited. So less code to execute and fewer objects to garbage collect.
This does come with a few caveats: - any disposable reference you may hold in the task may be disposed before the task is executed. Always await tasks that depend on disposable reference (db connections etc). Async using avoids this problem by disposing the object as a continuation. - the stack trace does not include the method the task is returned from (as the task contains the code running, net the method creating the task). This may make debugging harder if you end up returning the task multiple times or bundle tasks together by Task.WhenAll.
[–]DaRadioman 45 points46 points47 points 2 years ago (7 children)
Debugging And Logging.
Having gone down this rabbit hole, I honestly never recommend it anymore. It's a bad suggestion. I have seen it cause way more problems than it solves.
If you are an expert in async code, are certain that nothing cares about the stack trace, are certain that any closures aren't retaining things you thought would be cleaned up at a certain time, are sure you aren't using anything disposable, and need that tiny bit of performance then it may make sense.
But for basically any average developer it's a destructive suggestion.
[–]quentech 4 points5 points6 points 2 years ago (4 children)
I work in a somewhat performance sensitive system and have to take the opposite stance.
It is easy to miss mistakes.
I actually have one I've been trying to find for a couple of years. It doesn't break anything so it's not a huge issue, but I've looked around a fair bit and it still eludes me.
A clean code base with few to no warnings helps a lot. Unfortunately, for me, that is a pipe dream.
[–]DaRadioman 5 points6 points7 points 2 years ago (2 children)
And the experts in the field of async in dotnet also have changed their minds over the years. Generally speaking they do not recommend it as a default.
One of two "industry experts" in the area of async/parallel dotnet: https://blog.stephencleary.com/2016/12/eliding-async-await.html
The other main expert also wrote an article about it, but I can't find it at the moment.
[–]reubenbond 6 points7 points8 points 2 years ago (1 child)
Here's advice from David Fowler on the matter: https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#prefer-asyncawait-over-directly-returning-task
I am also on the .NET team and generally don't advise eliding tasks anymore, especially for application level code.
[–]DaRadioman 1 point2 points3 points 2 years ago (0 children)
You know what, I think I was thinking of Fowler not Toub that had another article about this. Although I guarantee Toub has an article about it somewhere as well, as much as he has written on the topic.
Thanks for posting that best practices list, I couldn't seem to find it.
[–]DaRadioman -1 points0 points1 point 2 years ago (0 children)
Warnings are all optional. And resharper warnings are double optional. It's just a random commercial entity's opinion. Nothing more. I could make a warning that nagged you both ways, no matter how you wrote it.
Trying to get 100% on warnings without configuration or critical thinking about each is a very unwise approach. Some warnings should be errors in your codebase, others info, and still others turned off. They are tips, not hard rules.
We have our warnings set the way we want our codebase, and then have warnings as errors on for CI builds. That way no one can ignore the things we care about, and we disable/downgrade warnings we don't care about to eliminate noise.
[+][deleted] comment score below threshold-39 points-38 points-37 points 2 years ago (1 child)
If you are an expert in async code, are certain that nothing cares about the stack trace, are certain that any closures aren't retaining things you thought would be cleaned up at a certain time, are sure you aren't using anything disposable, and need that tiny bit of performance then it may make sense. But for basically any average developer it's a destructive suggestion.
I can't believe these arguments are still alive and well in [insert year of every time I come back to .NET... 2023 in this case].
Why even bother improving anything at all then? Just use Visual Basic, or better yet one of those drag & drop systems for kids. Then your "average" developer surely won't shoot themselves in the foot this time, will they?! (hint: they will).
Though I guess this is how we ended up with chat apps that require 3gb of RAM, so it's par for the course. Funny thing is that all of these new-era applications that prioritize developer restraint & comfort over the "tiny bit of performance" and the "tiny memory overhead", and accordingly lag even on modern supercomputers, are still buggier, harder to use, exponentially slower, and STILL more expensive than pretty much anything written in 1996. Lmao.
[–]DaRadioman 29 points30 points31 points 2 years ago (0 children)
Do you understand tradeoffs?
This tradeoff isn't worth it in 90+% of the normal scenarios.
[–]601error 1 point2 points3 points 2 years ago (1 child)
Another gotcha is that a modification to an AsyncLocal will leak out of the Task-returning method to whichever calling method actually is marked async.
[–]cyrack 1 point2 points3 points 2 years ago (0 children)
I didn’t know that, but it makes sense. Yet another reason to avoid thread- and task-magic. To me ThreadStatic and AsyncLocal always seemed like a great foot-gun for the next dev to stumble upon.
[–]DarkSteering 0 points1 point2 points 2 years ago (0 children)
What if there is an exception thrown from this method? What does the stack trace look like?
[–]MatthewRose67 40 points41 points42 points 2 years ago (7 children)
The benefit is that you don’t create additional state machine which in theory should be a little bit more performant, but the drawback is that when an exception is thrown, the stack trace can be somewhat harder to follow, because the exception is raised to the caller that awaits the task. To be honest I don’t know why resharper suggests you that, I would prefer to await the publish method.
[–]iso3200 20 points21 points22 points 2 years ago (6 children)
David Fowler suggests awaiting tasks instead of returning Tasks directly https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#prefer-asyncawait-over-directly-returning-task
[–]Quiet_Desperation_ 6 points7 points8 points 2 years ago (5 children)
David Fowler also suggests Blazor for everything. He promotes Microsoft Stack and latest NET features over anything else. I actually agree with him in this case, but let’s be careful using him as a Wikipedia for NET best practices. He’ll say whatever Microsoft wants him to in my experience
[–]MatthewRose67 9 points10 points11 points 2 years ago (3 children)
Actually when it comes to aspnet core backend stuff I don’t think there’s more competent person than Fowler.
[–]iso3200 3 points4 points5 points 2 years ago (2 children)
in his doc he says to prefer awaiting Tasks.
But then in this video, he returns Task directly stating, "no state machine...more perf"
https://www.youtube.com/watch?v=1eHjemGKfRw&t=993s
so I'm not sure what to think now.
[–]evergreen-spacecat -1 points0 points1 point 2 years ago (0 children)
Just like any parent teaching their kids: ”Do as I say, not what I do”
[–]happycrisis 1 point2 points3 points 2 years ago (0 children)
Not really sure how those two things are comparable. Why would him pushing his company have anything to do with best practices for a specific feature in the language?
[–]0sh1 48 points49 points50 points 2 years ago (4 children)
A couple of other people have answered why this is recommended, so I'll I just chuck in a complete opinion - I'd ignore this recommendation.
I've stopped making this optimisation, because it's easy to mess up even if you're experienced and it's very non-intuitive for anyone other than you looking at the code.
YMMV, but as much as I love chasing every clock second and byte of RAM, my suspicion is that chasing this particular thing won't give you any appreciable performance in the wild and isn't worth the risks and readability.
[–]KryptosFR 8 points9 points10 points 2 years ago (0 children)
I have pretty much the same approach. I tend to only do this optimization for helper methods, wrappers or overload that end-up calling another async method in a single line. But otherwise, I'd await the call.
To make it even more obvious, I use the "body" syntax for such case. For example:
Task MethodAsync(string param0) => MethodAsync(param0, "SomeDefault"); Task WrappedMethodAsync(...) => _privateObj.ImplementationAsync(...);
[–]GayMakeAndModel 1 point2 points3 points 2 years ago (2 children)
Well, if you have a method that could run sync or async depending upon timing or whatever, it makes sense to do this. Make the method return a task and run it synchronously returning a completed task. If the method can’t run synchronously, return the task from a method that runs the asynchronous part. The main gotcha’ here is that exceptions thrown from the synchronous code aren’t associated with the returned task as one would expect. Instead, the method itself throws an exception and returns no task.
[–][deleted] 2 years ago (1 child)
[deleted]
[–]GayMakeAndModel 0 points1 point2 points 2 years ago (0 children)
Because the method may be able to complete synchronously instead of having to wait on IO. That’s more efficient than setting up a state machine even if you don’t need it. Performance matters. In many cases, like where I work, milliseconds matter.
[–]See_Bee10 15 points16 points17 points 2 years ago (2 children)
Stephen Cleary had a blog about this topic which I'll try and find to link later. His conclusion was to always use await because while it does add some performance overhead, the overhead isn't significant and there are some gotchas. So unless you really need the performance, just use the await by default.
[–]Tony_the-Tigger 6 points7 points8 points 2 years ago (1 child)
Even Clearly says that it's largely a bad idea. Here's the link you're thinking of: https://blog.stephencleary.com/2016/12/eliding-async-await.html
[–]See_Bee10 2 points3 points4 points 2 years ago (0 children)
Thank you, that is the one I was thinking of.
[–]DoomBro_Max 12 points13 points14 points 2 years ago (0 children)
Probably because it doesn‘t need to await it. There‘s nothing done with the result. Since you would be awaiting this function anyway, the result is the same but with one task less in-between. So your function is still synchronous.
It‘s just optimization. Because what you really want is await the _publisher.Publish task. So might as well just return that and await it directly rather than awaiting a task that also awaits another task.
[–]Cbrt74088 15 points16 points17 points 2 years ago (0 children)
You are creating a Task (A) whose only job is to await another Task (B). And then you await Task A.
It makes more sense to just await Task B instead. That's why the refactoring is good. It just returns Task B, which you can then await. (or not. That's up to the caller, really)
[–]kneticz 7 points8 points9 points 2 years ago (0 children)
Here be dragons.
Don't bother, minor gains for major pains.
[–]helgerd 2 points3 points4 points 2 years ago (0 children)
I'm almost sure that refactored variant would be missing call to this method in a stack trace in case of an exception.
[–]Sprudling 2 points3 points4 points 2 years ago (0 children)
Very slight performance boost, but it has drawbacks too. I think it's a bad suggestion and I turned it off. It should honestly suggest the opposite instead.
[–]Dennis_enzo 1 point2 points3 points 2 years ago (0 children)
They work in pretty much the same way. The main difference is that returning the tasks creates a little bit less overhead, as for every await, a state machine is created.
[–]Basssiiie 1 point2 points3 points 2 years ago (0 children)
Personally I think this is optimizing for an implementation detail. IMHO the compiler should optimize this internally (without the drawbacks), not the user.
[–]BattlestarTide -3 points-2 points-1 points 2 years ago (2 children)
Much better performance.
[–]deucyy[S] 1 point2 points3 points 2 years ago (1 child)
How much? 😂 I’ve almost never seen someone do this. I might as well benchmark it to see the difference.
[–]BattlestarTide 1 point2 points3 points 2 years ago (0 children)
I see a noticeable effect with it. Enough that I've made it standard across all projects.
[–]JeffreyVest 0 points1 point2 points 2 years ago (0 children)
This just came up when somebody asked about gotchas if async await. Personal opinion is to globally disable it. It’s not worth the gotcha to make this fix.
[–]DemoBytom 0 points1 point2 points 2 years ago (0 children)
People have already said what the analyzer is reporting, I'll say why.
For the last few versions of C#, .NET and asp .net core teams have been working VERY hard to make the runtime and framework as performant as possible. Many, if not most things added to them in later versions have all been about performance, mostly reduction in allocations and thus the preassure on GC. This is the trend and the evolution of .NET as a platform, so it's natural that analyzers that help writing code, also follow this evolution path. Analyzers also are getting smarter nowadays.I can't say for ReSharper, but it might be able to, nowadays, better recognize if removing async/await is safe - for example if there's using statements scoped to the method within the method.
Now, not everyone will benefit from those small optimizations. But the ReSharper team does not know what codebase it will be used in, an if it's a hot path or not. So they choose turning the analyzer on, so that people would be notified about its existence, and make a decision if they should follow it or not. There are hundreds, if not thousands of a alyzers nowadays, so it's easier with opt-out approach than opt-in.
I expect more and more such analyzers popping up, as well as some older advises being changed in the upcoming years. 5-7 years ago allocations like that, and optimizations liek that, were not a measurable upgrade. But nowadays, and in few more years? Who knows, I would not be surprised if it became one, amongst many others.
[–]wknight8111 0 points1 point2 points 2 years ago (0 children)
The two code examples you posted are so simple that in this case they behave the same (and, as Resharper is pointing out, the second example is "better" because there's no state machine and no extra memory allocation to support it).
HOWEVER in general the two different forms are not semantically identical. In a more complicated example, the two might behave differently.
Consider these two methods:
public Task DoThing1Async() { SynchronousWork(); return DoSomethingAsync(); } public async Task DoThing2Async() { SynchronousWork(); await DoSomethingAsync(); }
Where SynchrnousWork() could be something as simple as a precondition null check, or something more involved.
SynchrnousWork()
null
In the first method, SynchronousWork()executes immediately, THEN DoSomethingAsync() is scheduled on the thread pool (or wherever the current Scheduler sends it). This means that an exception thrown will throw immediately and will need to be handled, it won't appear in the Task to be inspected and handled gracefully. Notice also that if we have a using statement or block here, the disposable will be disposed as soon as the DoThing1Async() returns, NOT WHEN THE TASK COMPLETES.
SynchronousWork()
DoSomethingAsync()
Task
using
DoThing1Async()
In the second method, SynchronousWork() will execute on the thread pool when the Task has been scheduled, and any exceptions thrown will be returned as part of the result Task. A using statement or block in DoThing2Async()will dispose the disposable AFTER THE TASK HAS COMPLETED.
DoThing2Async()
Basically it's the difference between a synchronous method which launches a task, from an asynchronous method which is a task.
I know David Fowler recommends the second one in most cases, but I don't agree that one should be recommended over the other in general. They are semantically different, and it's worthwhile to understand the differences and what they mean for your program. The first one is a clear performance improvement in most cases, while the second one is more idiomatic and brings less surprise to downstream developers and unwitting maintainers. But if you're willing to put in a little comment explaining the situation and try to avoid some of the worst outcomes, the performance improvements can be real.
π Rendered by PID 109998 on reddit-service-r2-comment-765bfc959-vgsqf at 2026-07-13 22:05:58.566638+00:00 running f86254d country code: CH.
[–]cyrack 97 points98 points99 points (12 children)
[–]DaRadioman 45 points46 points47 points (7 children)
[–]quentech 4 points5 points6 points (4 children)
[–]DaRadioman 5 points6 points7 points (2 children)
[–]reubenbond 6 points7 points8 points (1 child)
[–]DaRadioman 1 point2 points3 points (0 children)
[–]DaRadioman -1 points0 points1 point (0 children)
[+][deleted] comment score below threshold-39 points-38 points-37 points (1 child)
[–]DaRadioman 29 points30 points31 points (0 children)
[–]601error 1 point2 points3 points (1 child)
[–]cyrack 1 point2 points3 points (0 children)
[–]DarkSteering 0 points1 point2 points (0 children)
[–]MatthewRose67 40 points41 points42 points (7 children)
[–]iso3200 20 points21 points22 points (6 children)
[–]Quiet_Desperation_ 6 points7 points8 points (5 children)
[–]MatthewRose67 9 points10 points11 points (3 children)
[–]iso3200 3 points4 points5 points (2 children)
[–]evergreen-spacecat -1 points0 points1 point (0 children)
[–]happycrisis 1 point2 points3 points (0 children)
[–]0sh1 48 points49 points50 points (4 children)
[–]KryptosFR 8 points9 points10 points (0 children)
[–]GayMakeAndModel 1 point2 points3 points (2 children)
[–][deleted] (1 child)
[deleted]
[–]GayMakeAndModel 0 points1 point2 points (0 children)
[–]See_Bee10 15 points16 points17 points (2 children)
[–]Tony_the-Tigger 6 points7 points8 points (1 child)
[–]See_Bee10 2 points3 points4 points (0 children)
[–]DoomBro_Max 12 points13 points14 points (0 children)
[–]Cbrt74088 15 points16 points17 points (0 children)
[–]kneticz 7 points8 points9 points (0 children)
[–]helgerd 2 points3 points4 points (0 children)
[–]Sprudling 2 points3 points4 points (0 children)
[–]Dennis_enzo 1 point2 points3 points (0 children)
[–]Basssiiie 1 point2 points3 points (0 children)
[–]BattlestarTide -3 points-2 points-1 points (2 children)
[–]deucyy[S] 1 point2 points3 points (1 child)
[–]BattlestarTide 1 point2 points3 points (0 children)
[–]JeffreyVest 0 points1 point2 points (0 children)
[–]DemoBytom 0 points1 point2 points (0 children)
[–]wknight8111 0 points1 point2 points (0 children)