"Stop Using Async Await in .NET to Save Threads" | Code Cop

แชร์
ฝัง
  • เผยแพร่เมื่อ 8 ม.ค. 2025
  • Until the 20th of May, get our new Deep Dive: Microservices Architecture course on Dometrain and get the Getting Started course for FREE!: dometrain.com/...
    Become a Patreon and get special perks: / nickchapsas
    Hello, everybody, I'm Nick, and in this video of Code Cop I will take a look at a newsletter post on LinkedIn that contained some pretty bad advice regarding Lists, memory and async await!
    Workshops: bit.ly/nickwor...
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: github.com/Elf...
    Follow me on Twitter: / nickchapsas
    Connect on LinkedIn: / nick-chapsas
    Keep coding merch: keepcoding.shop
    #csharp #dotnet #codecop

ความคิดเห็น • 244

  • @antonmartyniuk
    @antonmartyniuk 8 หลายเดือนก่อน +430

    Stop using your PCs, save the electricity

    • @futurexjam2
      @futurexjam2 8 หลายเดือนก่อน +1

      :)) I will loose also my private jet :)

    • @testitestmann8819
      @testitestmann8819 8 หลายเดือนก่อน +33

      Avoid bugs - stop writing code

    • @DemoBytom
      @DemoBytom 8 หลายเดือนก่อน +10

      To be fair, my PC is my main space heater as well.. So I kinda am saving electicity while using it? :D :D :D

    • @xorxpert
      @xorxpert 8 หลายเดือนก่อน +3

      stop using electricity, use solar energy

    • @discbrakefan
      @discbrakefan 8 หลายเดือนก่อน

      Yeah get a Mac 😂

  • @EikeSchwass
    @EikeSchwass 8 หลายเดือนก่อน +59

    We actually had thread pool exhaustion in production. The reason was an Oracle-DB with EF (Core) paired with async/await. Oracles provider doesn't support true callbacks and just blocks threads, until the database operation completes (basically Task.Result under the hood). So although async/await is not the issue per se, in combination with that oracle garbage it caused massive issues for us

    • @lizard450
      @lizard450 8 หลายเดือนก่อน +2

      I also ran into an issue with this when working with sql lite a few years back. Maybe I'll fire up the old project update the packages and see if I still can get the issue.

    • @VINAGHOST
      @VINAGHOST 8 หลายเดือนก่อน

      I thought only sqlite has this problem

    • @JacobNax
      @JacobNax 8 หลายเดือนก่อน +3

      That also happened to us with StackExchange Redis due to a bug x)

    • @eddypartey1075
      @eddypartey1075 8 หลายเดือนก่อน +1

      ​@@JacobNax how do u face this issue with StackExchange Redis? I'm curious

    • @Rick104547
      @Rick104547 8 หลายเดือนก่อน

      And this ppl is why you shouldn't block in async code.
      If it was implemented that way you would indeed be better off without async await.

  • @tymurgubayev4840
    @tymurgubayev4840 8 หลายเดือนก่อน +54

    normal brain: List
    galaxy brain: List
    (old brain: ArrayList)

  • @maacpiash
    @maacpiash 7 หลายเดือนก่อน +22

    11:08 "...David Fowler, who's basically, God..."
    Truer words have never been said 🙌🏽

    • @jasonenns5076
      @jasonenns5076 7 หลายเดือนก่อน +2

      Calm the blasphemy down.

    • @gnack420
      @gnack420 7 หลายเดือนก่อน +3

      ​@@jasonenns5076 sorry, let me correct: "David Fowler, who is literally God"

    • @mrjamiebowman
      @mrjamiebowman 7 หลายเดือนก่อน

      I died laughing when he said that.. there's an element of truth to that.. lmao..

  • @ChristopherJohnsonIsAwesome
    @ChristopherJohnsonIsAwesome 8 หลายเดือนก่อน +2

    I only used List once when I wasn't sure what I was getting back from reflection. That was before I learned better ways to handle that situation.

  • @pali1980
    @pali1980 8 หลายเดือนก่อน +3

    in addition to the issues with point 1), there would be no boxing involved when storing strings inside of a List as strings are reference types (even though they do have some behaviours from value types), so even that example does not work

  • @Chainerlt
    @Chainerlt 8 หลายเดือนก่อน +17

    TLDR; always use "using" with disposable objects when you can (unless you're doing something very fancy and you're fully aware how to handle these specific cases).
    The idea behind "using" with disposable objects is to prevent memory leaks in several ways:
    1 - people not always know what is needed to be done for a proper object cleanup, and even if they think they do, because maybe they looked inside the source for that particular disposable class, it might change in the future. In the example of sql connection it might no longer be enough to call Close(), because you're are not aware that package developers added something more in the dispose method.
    2 - people might not be aware of things which can throw exceptions before they manually clean the object, thus it can lead to memory leaks with dangling handles to unmanaged resources and etc.
    3 - properly implemented dispose pattern also makes destructor to call dispose method, thus GC will call it anyway for undisposed object and this can result in some unexpected behavior (this depends more on the implementation and ownership of disposable objects).

    • @DevelTime
      @DevelTime 8 หลายเดือนก่อน +3

      "The idea behind "using" with disposable objects is to prevent memory leaks in several ways:". It is much better to say "resources", because once you start associating disposing with memory, you are shortcuting its actual purpose.

    • @mk72v2oq
      @mk72v2oq 8 หลายเดือนก่อน +11

      The biggest flaw is that C# does not indicate disposables in any way. You need to memorize which classes are disposable. Compiler does not produce warnings if 'using' is omitted.

    • @protox4
      @protox4 8 หลายเดือนก่อน

      @@mk72v2oq There has to be an analyzer that does that already.

    • @billy65bob
      @billy65bob 7 หลายเดือนก่อน +6

      It's less about leaks (the GC will get around to it eventually).
      it's more with dealing with unmanaged resources (i.e. things the GC isn't aware of, such as Drawing.Bitmap), and depending on what you're doing, returning resources when you're done (e.g. SqlConnection, Mutexes, File Locks, etc), or finalising things where appropriate (e.g. MVC uses it to write the closing tags for HTML renders, Streams to Flush).
      The latter 2 are critical; for the former, improper disposal can and **will** make your app stall indefinitely if there is insufficient GC pressure, and not doing the latter will make you output garbage.
      Also if you want some inspections, I believe Roslynator has several around IDisposables to augment the ones in VS itself.

    • @alfflasymphonyx
      @alfflasymphonyx 7 หลายเดือนก่อน

      @@mk72v2oq this is absolutely right. There ought to be an indication at least at compile time if the object calls dispose somewhere in the code. And to be honest, if a class uses un managed memory, it is not my responsibility to clean it! The destructor of the class implementing the IDispose should free the memory it used. The IDispose should force the use of dispose method in the class. Using the class, I should not need to use using. I do not care what and how things are made inside that class really.

  • @NickMaovich
    @NickMaovich 8 หลายเดือนก่อน +40

    "Seed with random number" while there is 420 will never not crack me up :D

  • @Drachencheat
    @Drachencheat 8 หลายเดือนก่อน +23

    When the advice is so outrageous that your pullover transforms into a t-shirt

    • @parlor3115
      @parlor3115 8 หลายเดือนก่อน +1

      That's actually welcome since it's getting really warm in here

    • @maacpiash
      @maacpiash 7 หลายเดือนก่อน +1

      Watching the video from Australia, I appreciate his t-shirt being transformed back into the pullover.

  • @magnusm4
    @magnusm4 4 หลายเดือนก่อน

    What's comforting to learn and know is that over language's time, they've been optimized.
    And what's good to remember is that during compiling. They've been so smart as to make the compiler run through the code and change your code, internally.
    To what it finds more optimal. So if you use a switch statement. And it thinks "mmmh I don't think so my dude". Then it will change it to if statements if it finds it more optimal in that situation.
    It makes writing fast code much easier and you get a smaller gap between safe but not optimal code, and unsafe memory but more flexible and fast code like C++.

  •  หลายเดือนก่อน

    WPF uses object collections extensively, and reflection to handle property binding. I also use List for variants, like with custom database entity libraries or Win32 APIs that can return any type.

  • @billy65bob
    @billy65bob 7 หลายเดือนก่อน +2

    I actually have used List before.
    I was converting some old codefrom ArrayList to List so I could actually understand what was going on, and there were collections that were being used for 2 or more distinct and completely contradictory types.
    I didn't want to deal with that at the time, so ArrayList -> List it was for those.
    On the other hand, that refactoring also revealed about a dozen bugs before I even got around to the changes I had wanted to do, lol.
    I have also used it in the form of Dictionary when I was building a thing to load a configuration file, and use said configuration to build a completely arbitrary nested data structure.
    The result of which was serialised into JSON to send off elsewhere.

    • @ScottKFraley
      @ScottKFraley 3 หลายเดือนก่อน

      Given the whole "used for 2 or more distinct and completely contradictory types" thing, I'm a bit surprised you didn't go straight to a Dictionary kinda thing. I do of course see that you have in other situations, and I have very little other context so.. just say'en I guess. :D

    • @billy65bob
      @billy65bob 3 หลายเดือนก่อน +1

      @@ScottKFraley it was for a printing function.
      I probably could've just made a 2nd collection...
      Basically when generating a printable document, 98% of client code and 100% of server code used the correctly typed objects.
      There were a few spots client side that just put the DTOs in there... But they worked correctly and I didn't want to do even more refactoring.

  • @viper110110
    @viper110110 5 หลายเดือนก่อน +1

    #2 used to be an issue in the CLR for XNA Game Studio on the xbox 360. Using a foreach would do an allocation for each item in your collection, triggering the garbage collector far more often than you'd want. for loops were the solution. Of course that was 2009 and things are much better now.

  • @ryan-heath
    @ryan-heath 8 หลายเดือนก่อน +4

    Actually ...
    using (...) is preferable over manually disposing objects.
    In case of exceptions, the scared unmanaged resources (for instance, db connections) are given back or closed,
    to be used by other waiting tasks.

  • @CharlesBurnsPrime
    @CharlesBurnsPrime 7 หลายเดือนก่อน +1

    I use IEnumerable often, for the specific case of executing SQL with Dapper for which the nature of the results are not known at compile time, but I have never seen a List outside of deep library corner cases.

  • @Ivolution091
    @Ivolution091 8 หลายเดือนก่อน +4

    Thanks for referencing to David Fowler's AsyncGuidance article!

  • @bslushynskyi
    @bslushynskyi 7 หลายเดือนก่อน

    I used List in scenario where list was used as bucket for various objects which stored some results of various part of application and for some specific operation looped through that list checking type and perform final calculations accordinly. It was back in Window Forms and C#4.0, I think. However, I would rather say that I did it this way because I didn't know better one back then.

  • @ThomasJones77
    @ThomasJones77 8 หลายเดือนก่อน +12

    Using List instead of List when you know only strings will be stored doesn't make sense. However, there are many cases where List or object[] makes perfect sense in .NET right now, and in fact there's no other way at times.
    It seems some devs deal with a limited amount of code paths/scenarios to say they can't *ever* see any usage beyond old code, or have never used it.
    Just off the top of my head, if you have any code that needs to collect data to invoke various methods via reflection, List is a must for collecting values to pass into those methods.
    There are other scenarios where one may build a specific serialization background service to conform objects for audit or storage where strongly typing the class makes no sense.
    There are several other scenarios that make sense off the top of my head also, but I'll move on.
    List should only be used when it makes sense. It should never be used when the type is known, or if an interface or base class type can be used for differing types. Obviously, boxing value types *unnecessarily* should be avoided.

    • @manilladrift
      @manilladrift 8 หลายเดือนก่อน +6

      Hot take: If you're using List, it's because you lack the technical expertise required to build a solution in a maintainable, type-safe way. Honestly just a skill issue on your part.

    • @ThomasJones77
      @ThomasJones77 7 หลายเดือนก่อน +2

      @manilladrift Real Hot Take on your so-called hot take: BWAHAHAH.
      Absolutely wrong @manilladrift . If you make comment that implies "there is *never* a reason to code in such a way" then it's you, *honestly it's you*, who not only lacks technical expertise, but you also lack coding experience.
      While object[] can often be used instead of List there are scenarios that *a developer with actual technical expertise* will recognize the latter is better.
      There's a reason reflection invocation calls to methods use an object[] parameter. It's because methods have parameters of any number of types.
      Now, follow what I'm about to say so you can gain some knowledge. If you have an object[] in .NET's method invocation reflection call because the parameters can be of mixed types when invoking a method, SCENARIO 1: if you at *run-time* need to collect data of varying types for a method invocation that itself is also determined at run-time, which has an object[] parameter in addition to other parameter types, then *List* is perfect for that scenario. There's other details about the invocation that solidifies that as being perfect too, but what I mentioned sufficiently demonstrates it as preferable if you understand.
      That scenario is for a system that collects live data as a conversation is being monitored for specific words. Various word are connected to various types, and those types are collected in real-time. Various word combinations then trigger the need to invoke various methods determined at runtime that have varying parameters counts & types, passing in various metadata types as individual parameters. Those methods then do their work providing valuable info for speakers in the conversation. A complete success.
      If you have in your mind "*nEVeR* uSe *List* because sOMebOdY said 'aLWayS bAd'" then you'll probably try allocating an object[] with a probable size and resizing object[] as needed like the code behind List would similarly do, instead of simply using List, which is optimized already, to collect the data as it came in. Using *List* to collect that data of varying types as it came in would be the proper approach for that scenario. Your assertion @manilladrift, with just one scenario of many, is wrong.
      Whether you think a particular design is good or bad, extreme or otherwise, there are proper scenarios in good designs and bad designs where using List is proper for the particular design in use. *Understanding that comes with maturity @manilladrift.*
      Your reasoning is why people say silly things in YT videos like "there's *NEVER* a good reason to use async void or Task.Wait." While the use cases may be extremely limited, saying "never" simply demonstrates one's lack of expertise & experience. Your comment has exposed yours.
      Good day.

    • @manilladrift
      @manilladrift 7 หลายเดือนก่อน

      @@ThomasJones77 I'm sorry, I disagree completely. I believe there is always a smarter, more type-safe way to represent diverging types by aggregating common or expected traits into separate type definitions. Using a List is simply a bad design decision that shows the developer is simply unable to come up with a smarter solution. Again, it's a skill issue.

    • @flow-2606
      @flow-2606 7 หลายเดือนก่อน

      @@ThomasJones77 you have varying types and you dont know when and it what order they occur, but as a programmer you still know what kind or pool of types you could expect, right? so cant you just create an interface like ICollectedData or something that all known types implement? even if the types dont share a common functionality defined in the interface, wouldnt an empty interface still vastly improve the code readability?

    • @ThomasJones77
      @ThomasJones77 7 หลายเดือนก่อน

      @@manilladrift As an exercise, rewrite the .NET method invocation code (*MethodInfo.Invoke(...)*) to be strongly typed only, eliminating object and object[]. Just something as basic as that demonstrates that it is you who lack the skill and experience.
      There are simply instances where things do not need to be strongly typed as you insist. You say it's bad design and the developers of .NET should have come up with something better, but you can only make such an assertion if your skill and experience level with various coding scenarios are limited.
      The use of List for collection to populate various parameter types of various methods that are determined at runtime is just ONE example of many.

  • @davestorm6718
    @davestorm6718 7 หลายเดือนก่อน +1

    try - catch, definitely. I write tons of I/O stuff and exceptions don't always happen when you think they will. For example, you can test a file to see if it has locks (or whatever), then believe that everything will be okay when you start reading it (big file), half-way in the read, a network card crashes (or drive hiccups, or what-have-you), then your IF check is worthless, and your program crashes because you didn't use exception handling. Believe me, stability is FAR more important than SPEED. A slow program is a nuisance, but a crashing program can be a career changer!

  • @makescode
    @makescode 8 หลายเดือนก่อน +2

    The further irony of the first example is that it talks about the potential problems with value-type boxing and then uses "List" as the better alternative.

  • @apsdev3248
    @apsdev3248 2 หลายเดือนก่อน

    This guy is absolutely the best programmer in the world. Listen to him if you want become the best. He is part of all dev teams in MS

  • @funkwurm
    @funkwurm 8 หลายเดือนก่อน +1

    I've used List when I didn't know the actual runtime type as my understanding is that it doesn't box but actually looks at what the type is at runtime and treats it like that type after that.
    Curious about whether my understanding is correct.
    (For context, the runtime types were all of Expression and List didn't work)

    • @SG_01
      @SG_01 8 หลายเดือนก่อน +1

      List gets converted into List under the hood. The compiler will then add code to dynamically resolve whatever you are trying to do with that type. Have a look at sharplab to see what the code gets lowered to, it is really interesting.

  • @David-id6jw
    @David-id6jw 8 หลายเดือนก่อน

    @7:00 - One thing I'm seeing a good case for in eliminating this "control flow" use of exceptions is in object creation. In particular, a more functional approach helps reduce this.
    Many class types throw exceptions when doing data validation in the constructor (eg: ArgumentNullException.ThrowIfNull(myParameter)). The problem is that there is no other way to indicate failure when you're doing the validation in the constructor, so you _have_ to handle it via exception. A more "functional" approach (according to some) is to remove the data validation from the type itself, and only ever create the object through a Create() function (generally through a static class which specifies exactly what expectations it has about the types of objects it creates when using the result object type). The Create() function does the validation, and can return a null if validation failed, rather than throw an exception. The type itself can never throw because it never does any validation in the constructor.
    This then makes the idea of switching to an if/else block instead of a try/catch block make more sense, at least when you're creating objects.

    • @username7763
      @username7763 8 หลายเดือนก่อน +1

      I think it depends on the purpose of the class. If the class is really an abstract data type that has to preserve the consistency and integrity of the data within it, it should really throw in the constructor. e.g. it shouldn't be possible to construct an array type of length -1. This significantly helps reasoning about code using it not having to worry about if the state is valid. There can be good cases for a factory method, but generally when you might have different kinds of factories or different creation logic. I hate having a Create function just in place of a constructor, it is unexpected compared to everything else.

    • @David-id6jw
      @David-id6jw 8 หลายเดือนก่อน +1

      @@username7763 Oh, certainly. And at the most fundamental levels those kinds of protections are necessary.
      I think it's a matter of "validation" vs "not even representable". A null value for an array, or a length of 0, may not pass validation, but it's representable. An array with a length of -1 isn't even representable.
      I'm trying to adapt to a more "functional" style (basically, seeing how well a certain set of recommendations works vs how I normally write code), and the assertion is that the type is just a type, and shouldn't validate itself. The validation is moved to a separate class's factory methods. Though I think it works better from the grounds of using records as data types, rather than full classes. Behavior is lifted out of the type, rather than encapsulated by it as in standard OO.
      In that manner, you have the 'factory' class and say, "I'm going to use this type in this manner. Please make one for me." And if it's not able to (it fails validation), it returns null, and you don't have to deal with exceptions, just 'if' checks. And nullability warnings in the tooling make it easier to spot where you failed to make sure you got a valid object. If you didn't catch an exception, that could end up being handled anywhere. It's not an error to not catch the exception (at least until the program crashes).
      That also allows you to create a second factory class that generates the type using different validation considerations, and you don't have to figure out how to make both configurations work within the constructor of the type itself. (Just like an int is just an int, and doesn't care if you're using it to represent an Age value that can't be negative.)
      I've also found that it's much easier to reason about object creation when the Create() function can be named in a way that explains why it's being used. Compare with having multiple constructors with varying parameters, expectations, and validations; a "new MyObject(~params)" doesn't give you a clue about any such differences, but a Create() vs CreateWithNameOnly() can be a useful distinction.

    • @username7763
      @username7763 8 หลายเดือนก่อน

      @@David-id6jw Wow that was a lot to write in the comments section! I think I followed it though. Yeah what you describe makes sense from a function programming style.

  • @Nobonex
    @Nobonex 8 หลายเดือนก่อน +4

    0:58 If only I'd been so lucky haha. Currently maintaining a codebase where the previous developer didn't seem to like type safe languages. Objects and dynamics everywhere for no apparent reason.

    • @jfftck
      @jfftck 8 หลายเดือนก่อน +2

      Sounds like a JavaScript developer.

  • @AtikBayraktar
    @AtikBayraktar 7 หลายเดือนก่อน

    12:50 we don't have to manually dispose our injected dependencies including DbContext? built-in dependency container does that for us for each object lifetime, am I right?

  • @DevLeader
    @DevLeader 8 หลายเดือนก่อน +8

    I suspect this is written by AI primarily, for three reasons (there are probably more):
    - the advice on loops is outdated and those optimizations are within last few years
    - the advice overall is kinda sloppy, kinda just... Stuff that you can say with confidence and people might agree.
    - The word "judiciously" is extremely uncommon, unless you're using an LLM
    Nothing wrong with using AI to support your writing but... You still need to read it.
    I don't know who wrote the newsletter, and I mean nothing negative by commenting, but I'd suggest more thorough investigation/proofing when using AI tools.

    • @thebluesclues2012
      @thebluesclues2012 7 หลายเดือนก่อน +3

      Spot on, shows the poster doesn't code, so it's junk, there's gonna be more of these junky articles.

    • @duramirez
      @duramirez 7 หลายเดือนก่อน +2

      I am so tired of the AI trend. Everything in my office now people say: oh chatGPT can do that. Geeeez can people be MORE lazy? ffs no one wants to do stuff anymore. :(

  • @jongeduard
    @jongeduard 8 หลายเดือนก่อน +1

    I would even say, the whole point of async await is that it does NOT cause threads to block. For that same reason it's designed to PREVENT thread pool starvation. So it's literally the opposite of what they wrote there.
    If you still experience problems, it's a sign that you do things wrong. A possible cause is calling GetAwaiter().GetResult(), Result or Wait in your code, which causes multiple threads at the same time to hang.

  • @dgtemp
    @dgtemp 7 หลายเดือนก่อน

    I have used the 1st point in one of my endpoint which basically is a lookup fetched dynamically based on params.
    Previously I had used EF Core but as you know it doesnt have generic entity types and the code is also a mess with a lot of if else statements / switch statements.
    I switched to dapper with sqlbuilder and revamped the endpoint to generate query dynamically based on params with return type as object (obviously because we dont know what the return type of the fetched lookup is).
    Also not to mention I have a table which has all the lookup entries and their respective columns to be fetched. So that is also dynamic and can be changed however you like. Hence the IEnumerable

  • @afroeuropean5195
    @afroeuropean5195 7 หลายเดือนก่อน

    Regarding boxing around 1:20
    All the integers stored in a List will still be stored on the heap, not on the stack
    Btw, not disagreeing with the argument that you should still use the explicit type to avoid boxing and type juggling at runtime

    • @QwDragon
      @QwDragon 7 หลายเดือนก่อน

      Ints won't be boxed in List, but in List they will.

    • @afroeuropean5195
      @afroeuropean5195 7 หลายเดือนก่อน

      @@QwDragon correct, I was just replying to the statement about value types usually being stored on the stack. That is not the case when the value type is a member of a reference type

    • @blackenedsprite8542
      @blackenedsprite8542 7 หลายเดือนก่อน

      Further to above, the defining characteristic of value types is not where they are stored, it's that their type and value are stored together.

  • @David-id6jw
    @David-id6jw 8 หลายเดือนก่อน

    @6:00 - Just a note. I looked at this when you did your last video on loop performance, but my own benchmarking does not show any benefit to uplifting the size of the array/list/whatever instead of just using it in the for loop directly.
    SharpIO does show that there are more compiled instructions (something like 5 instructions out of 20, IIRC) if you leave the .Count or whatever in the loop function, but performance was nearly identical - at most a 0.5% difference. I suspect it gets optimized out once it runs a few times. There's also the question of which one better allows eliding bounds checking. In theory both should, but I've encountered some indications that uplifting the count sometimes loses that optimization (or at least didn't used to a few versions ago).
    EDIT: And Stephen Toub was in an interview video that just got uploaded an hour ago, and mentioned a tool called disasmo which gives you the actual final assembly output of the JIT. Using that, I see that there's only a one-line difference between the lifted and unlifted versions of the loop. That difference is just assigning the list size into a different (additional) register, which leads to a slight shuffling of which registers are used in the rest of the code. The loop itself is identical, aside from the names of the registers.
    So lifting the size of the list out of the for loop does basically nothing.
    EDIT 2: Also also, just switch to a span if you need performance. The same benchmark is twice as fast as the default one if you marshal the list as a span. The number of assembly instructions for the loop section is halved (5 vs 11).
    Basically, lifting the size accessor out of the loop provides no performance benefit, and if you really need extra performance, switch to a span.

  • @itsallgravy_9437
    @itsallgravy_9437 8 หลายเดือนก่อน +1

    List = NO!
    Autocomplete/refactoring will take care of the hassle of creating the new class(es)...use it. Create that class with a name that makes sense, then populate that nice new reference type with properties as you need...

  • @tlcub4bear
    @tlcub4bear 7 หลายเดือนก่อน +1

    12:47 what magic did you use to show the code underneath?

  • @davidmartensson273
    @davidmartensson273 7 หลายเดือนก่อน

    I have only used the likes to List when deserializing unknown list data, or in some adhoc code where I needed to have lists of unrelated types, but even in those cases I usually find better solutions.
    And I do not really recall any colleague ever using List without a good reason and understanding of the implications.

    • @davidmartensson273
      @davidmartensson273 7 หลายเดือนก่อน

      @@mattyward1979 In this case its not data from external sources but rather for some generic debugging or as I mentioned, adhoc parsing to easier identify what types I do need to map out the correct type of objects.
      In production code I would not trust that kind of code, even without the security problems :)

  • @username7763
    @username7763 8 หลายเดือนก่อน +1

    The exception handling comment got me thinking. Does anyone know a good reference for how the internals of .Net process exceptions? I'm used to the C++ / Windows world where they use SEH. The value of SEH is being able to have exceptions work properly even between calls written in different languages or compliers. But SEH is known for having a large-ish performance hit. I would think that the CLR doesn't need it for dotnet code. Plus SEH is Windows only. How does dotnet since .net core handle exceptions?

  • @loganyoung228
    @loganyoung228 4 หลายเดือนก่อน

    I'm a self taught developer with 20 years of professional experience. Since 2021, I've been developing and managing full stack applications for a healthcare provider in my city as the only dev employed by the company. I have never in, my entire career, used the object type explicitly. If I need a string, I declare a string; if I need a list of strings, I declare a list of strings. I don't use object and I don't even use dynamic either. Being self taught I am, regrettably, unaware of the benefits or uses of these types. I don't know what they're for exactly, so I don't use them.

  • @martinprohn2433
    @martinprohn2433 8 หลายเดือนก่อน

    In your example of HttpClient and async await, the HrtpClient is but using await and therefore but preserving the stack, but that is also not necessary, because the calls are just cause the overloads with more parameters. So the stack would be smaller, but actually better because it would contain less noise.

  • @Hakkology
    @Hakkology 5 หลายเดือนก่อน

    How about List ?
    What can we use instead ? I've been working on an old code base and i see this thrown around so very often.

  • @pcdizzle13
    @pcdizzle13 8 หลายเดือนก่อน +4

    A real async problem you’ll almost certainly run into, especially in distributed systems using http client is not thread exhaustion but socket exhaustion. Using statements are actually bad on http client. Make sure to re-use your http clients, the easiest way to do so is http client factory, or something super simple like a static http client that gets re-used .

  • @username7763
    @username7763 8 หลายเดือนก่อน

    I didn't know that about the async / await creating a state machine and a little extra execution time between examples. To me, logically the returning a task and awaiting on it are exactly the same and I assumed the compiler created the same code for both. I knew there was some state machine logic with async but I assumed only when there were multiple awaits. Very interesting! I learned something new here.

  • @alexandernava9275
    @alexandernava9275 8 หลายเดือนก่อน

    I have only seen List for not knowing type. Though I will say, I would lean generics if you don't know the type.

  • @_tanoshi
    @_tanoshi 8 หลายเดือนก่อน

    i actually had to use List quite a bit when dealing with some quirky stuff in WPF... but that was because they do not support generics for did not support it at the time i was dealing with that, for my use-cases. it was really annoying to deal with

  • @jimread2354
    @jimread2354 8 หลายเดือนก่อน

    It's not a List, but the built in System.Data.DataRow is an object[], as are the parameters for a command line application.

  • @DxCKnew
    @DxCKnew 8 หลายเดือนก่อน

    If you choose to utilize async/await in your code, it should be for all waiting or IO-based calls across the board, including in all the libraries you use. Otherwise you risk running into thread exhaustion even for one synchronous wait call, since each call like this will block an entire thread-pool thread until it finishes.
    In this context, it's very bad that Microsoft did not implement awaitable Directory.CreateDirectoryAsync() or File.DeleteAsync().
    For the same reason, don't ever call a synchronous wait or IO-based calls on a thread-pool thread.
    If there is no way around it, use a non thread-pool thread for blocking calls like this.

  • @SeanLSmith
    @SeanLSmith 8 หลายเดือนก่อน

    Have seen List once before, yet as you said, it was when the inbound data was unstructured/mangled. From there the code would try and cast it to a class type to see if there is any valid data and datatypes that the code cared about to continue logic checks later on. the code was not great and would not recommend.

  • @Sebastian----
    @Sebastian---- 8 หลายเดือนก่อน

    Question: [12:52] Why is there the try-finally-block in the IL-Viewer?

    • @arjix8738
      @arjix8738 8 หลายเดือนก่อน +1

      because the using statement is not part of the dotnet runtime, it is just syntactic sugar
      It is translated to a try/finally so the runtime can execute it

    • @AlmightyFuzz1
      @AlmightyFuzz1 8 หลายเดือนก่อน

      Look into the concept of Lowering in C#, Nick has a great video on this. In a nutshell the C# code you write (the using statement and many other things) gets "compiled" into low level and usually optimised C# code that gets run by the runtime.

    • @ErazerPT
      @ErazerPT 8 หลายเดือนก่อน

      @@arjix8738 Yes but not just. Same as lock() and (somevar as sometype), using is syntactic sugar. Just a sign that WAY too many people didn't do things properly so they shortcut'ed it and now people don't know the difference between .Close and .Dispose. And most don't even know what a destructor is, god bless them for working in 100% managed land... The "not just" part is "whatever happens inside using .Dispose MUST be invoked, as that is the sole purpose of using. And that's what finally{} does, call .Dispose whatever happens.

    • @ErazerPT
      @ErazerPT 8 หลายเดือนก่อน

      Not sure about the question, if it's about the code lowering or the functional part, but assuming the second, when you use using, the one guarantee you have is that WHATEVER happens, .Dispose is called. So logically try{something}finally{whatever happened call .Dispose}.

  • @deadblazer8931
    @deadblazer8931 7 หลายเดือนก่อน

    I've had never use List aside of list of unknown type before.

  • @dvdrelin
    @dvdrelin 8 หลายเดือนก่อน

    about finally section... it protects on all exceptions thrown, even ThreadAbortException.. pretty useful, isn't it? what if TAE will be thrown before .Dispose() (or Close, whatever) invoking?

  • @johnjschultz5414
    @johnjschultz5414 8 หลายเดือนก่อน

    I only use a collection of objects (List, Dictionary, etc) if the object is used by a lock statement. It's a rare case when I need it.

  • @michi1106
    @michi1106 8 หลายเดือนก่อน

    ArrayList was introduce with .net 2.0, before that there was no List-Type, only Arrays. So ArrayList was a big improvement for my project this time. But also, the object-type was bad, because i was forced to do a typecheck on every access on the List. So the later generic List was my dream.

    • @maschyt
      @maschyt 7 หลายเดือนก่อน

      According to the ArrayList documentation it was introduced with .NET Framework 1.1.

    • @michi1106
      @michi1106 7 หลายเดือนก่อน

      @@maschyt first comment was based on my memory, you are right, but at this time, i was just starting with C# in selflearning, so it still was an improvment for me :-)

  • @iSoldat
    @iSoldat 2 วันที่ผ่านมา

    The dev "manager" I replaced didn't use IOC, async/await, or any modern practices for that matter. Every time I open a legacy app he wrote, I have a mini-stroke. Rewriting the garbage he wrote is a massive undertaking.

  • @Zullfix
    @Zullfix 8 หลายเดือนก่อน

    I used an ArrayList instead of a List once.
    It was my 3rd project in C# and I didn't know any better.

  • @owenneilb
    @owenneilb 8 หลายเดือนก่อน

    This first piece of advice is probably targeted at newer programmers who aren't familiar with how to properly structure code. I see lots of posts on reddit from new programmers trying to struggle through homework and fighting the language end up doing things like use List because they don't figure out they need an interface or something. Not the greatest advice though, as the solution is usually add an interface or common base class, rather than "use List", which doesn't help solve the problem.

  • @GeorgeGeorge-u5k
    @GeorgeGeorge-u5k 7 หลายเดือนก่อน

    Guys how can i see the source code in VS from .NET apis like Nick did with HttpClient. When i press F12 i see only signature i don't see any code inside.

  • @MaximilienNoal
    @MaximilienNoal 8 หลายเดือนก่อน +13

    I put async await everywhere even when I could just return a Task. Come at me! 😁

    • @isnotnull
      @isnotnull 8 หลายเดือนก่อน +1

      HttpClient is a good example why you might avoid to do so. If you just run overloaded method from inside, you don't care about awiting it, because the overloaded method itself has logic in it which you are interested in

    • @rafazieba9982
      @rafazieba9982 8 หลายเดือนก่อน +3

      @@isnotnull ... but if you want a rule of thumb putting async/await always without thinking about it is a good one

    • @discbrakefan
      @discbrakefan 8 หลายเดือนก่อน

      Is there even a downside to this?

    • @billy65bob
      @billy65bob 7 หลายเดือนก่อน

      @@discbrakefan If you return the Task, that method doesn't get added to the Task's stack.
      So it's marginally cheaper to execute, but it also makes it marginally harder to debug because the stack trace won't show how the Call Site got to the Executing Method.
      As such I would generally recommend only using this in one very specific niche scenario: Forwarding a method without a CancellationToken to one that does, and only when the `default` keyword isn't applicable.
      e.g.
      Task MyMethod(params int array[]) => MyMethod(CancellationToken.None, array)
      async Task MyMethod(CancellationToken token, params int array[]) {...}

    • @isnotnull
      @isnotnull 7 หลายเดือนก่อน

      @@rafazieba9982 As a rule I assign a result of await to a variable and return the variable instead of expression. Helps in debugging at no performance cost

  • @IElial
    @IElial 8 หลายเดือนก่อน

    I'm using List/Dictionary for generic Deserialization (Json, xml, ...). Am I wrong to do so ?

    • @realsk1992
      @realsk1992 8 หลายเดือนก่อน

      I think it is usually better to use "JsonElement" instead of Object, because that is what is really there (if using System.Text.Json), and it will gain more power to you. As for XML, it might be XmlNode, and so on.

    • @IElial
      @IElial 8 หลายเดือนก่อน

      @@realsk1992 Actually it is the issue as I code an agnostic format's serializer so I cannot know in advance if it will be Json, XML, ... used by user.

  • @marvinjno-baptiste726
    @marvinjno-baptiste726 7 หลายเดือนก่อน

    I have used a List before, but had a specific reason for it, which probably could have been mitigated by using an Interface (but hey, it was years ago and I was new to that!) - but List?? Why :-/

  • @jimmyzimms
    @jimmyzimms 8 หลายเดือนก่อน

    "The term exception is the frequency of a situation, though it should be rare, but in taking exception in how they were used in this condition" -Jeffrey Richter

  • @QwDragon
    @QwDragon 7 หลายเดือนก่อน

    1. This advice could've been for VB_NET. There object can in some cases behave as C#'s dynamic. That means that list of object is kind of list of dynamic. Anyway, adwice to use correct type seems right. But there is another mistake there: string is not a value type, so it can't be example for boxing/unboxing.
    2. Agree, no reason to use for instead of foreach almost always. Alco not all collections do have known length.
    4. I think "excessive use" does mean that you have excaption in normal flow of work. For that case I completely agree with advice to avoid exceptions in normal flow and use them only for exceptional situations.
    6. Seems controversial, but the reasoning is actually strange.
    7. Close and dispose is the same thing in most cases. File streams are explicetely implementing IDisposable with Close method on own class and Dispose on interface. The point of adwice is in implicit handling by using statement instead of explicit close/dispose call. And the advice is right because of try-catch in recommended way. Check stackoverflow questions/answers for calling close - you hardly ever will see try-catch aroud it. And there is no point in writing all this stuff when it can be autogenerated by using using.

  • @Ch17638
    @Ch17638 8 หลายเดือนก่อน

    TF uses a list of object ? By the second item to me it is clear someone typed into chat GPT "generate 10 tips to increase performance on C#" and copied pasted it straight into linked-in.

  • @georgeyoung2684
    @georgeyoung2684 8 หลายเดือนก่อน +11

    “David Fowler who is basically… God” love it

  • @weicco
    @weicco 7 หลายเดือนก่อน

    About try-catch. It would be good to mention you need to only catch only those exception you are expecting, not all of them. Because exceptions are for cases which can be foreseen like user pulling ethernet cable out of the wall in the middle of file transfer. I've seen people doing heck size of try-catches to catch _programming errors_ probably because they don't want to show the end user how bad they are at writing codes and _tests_.

  • @hexcrown2416
    @hexcrown2416 7 หลายเดือนก่อน

    Json parser in a project i work on parses everything into obj where obj can be primitive or List or Dict i dont love it, but it works...

  • @arielspalter7425
    @arielspalter7425 8 หลายเดือนก่อน +1

    The last one, using “using”, is actually a good advice. I didn’t understand why you concluded it as a bad advice.

    • @firestrm7
      @firestrm7 7 หลายเดือนก่อน

      A good example for why critical thinking is a must-have skill. Nick usually resonates with me but this one seems not thoughtful.
      IDisposable is about releasing unmanaged resources and in that one you must trust the component and call Dispose - preferably using using :) - asap.

    • @anderskallin6107
      @anderskallin6107 7 หลายเดือนก่อน

      I don't think it was the using statment he thought was wrong, but how the "mistake" called the Close-method, which is not the same as calling the Dispose-method.

  • @David-id6jw
    @David-id6jw 8 หลายเดือนก่อน

    I was updating some old, old code recently, and found it was still using ArrayLists for things that could be moved to generics. Was a bit embarrassing, even if I know I wrote that in the .NET 1.1 days.

  •  8 หลายเดือนก่อน

    On async/await vs returning the task, there are at least two big things to consider... I can only see one addressed here, the difference in stacktrace. The other one is throw vs rethrow of exceptions.

  • @bankashvids
    @bankashvids 7 หลายเดือนก่อน

    This was a good one. Thanks!

  • @martinprohn2433
    @martinprohn2433 8 หลายเดือนก่อน

    I thought ArrayList is just still there because of downward compatibility and should not be used anymore.
    (I actually used it once in WPF, because it is easy to create in XAML; but that was already over 10 years ago).

  • @jinekLESNIK
    @jinekLESNIK 5 หลายเดือนก่อน

    Why they put string to showcase boxing? string is reference type.

  • @tvardero
    @tvardero 8 หลายเดือนก่อน +2

    List of objects might be used when theres not base class in items you want to hold, but they are still have common usages. In my case this is for COM library for some WinForm application, they have custom components that do not have base class (so they are stored in object collection).
    Second situation could be when I'm dealing with open generic interfaces, that also do not have base interface. Or when in some rare case non-generic interface implements generic one with type object. Happens.

  • @ismailosman5048
    @ismailosman5048 7 หลายเดือนก่อน

    List ....... Never

  • @zbaktube
    @zbaktube 8 หลายเดือนก่อน

    Hi! Kind of did it: List objects = ... 😀

  • @luciannaie
    @luciannaie 8 หลายเดือนก่อน

    where did you get these from? I want to see that LinkedIn post :)

  • @MrDuk-rk4ne
    @MrDuk-rk4ne 7 หลายเดือนก่อน

    I’ve been a dotnet dev for 12 years and I’ve never ran across a List outside of very specific cases

  • @mikeblair4545
    @mikeblair4545 8 หลายเดือนก่อน

    Personally the best advice i can give is to stop typing out stringbuilder and just type out string. By not making your progam compile builder you save 7 characters, making your application smaller.

  • @BrankoDimitrijevic021
    @BrankoDimitrijevic021 7 หลายเดือนก่อน

    Not sure why the last advice is “bad”. Quote from the docs:
    “If the SqlConnection goes out of scope, it won't be closed. Therefore, you must explicitly close the connection by calling Close or Dispose. Close and Dispose are functionally equivalent.“
    So, disposing a connection is a perfectly legal way of closing it, so why wouldn’t you wrap it in `using` for exception safety?

  • @MarvinKleinMusic
    @MarvinKleinMusic 8 หลายเดือนก่อน +1

    I'm using a List of objects to store different type of classes within a memory cache so I don't need to call a database for everything which rarely changes

    • @Biker322
      @Biker322 8 หลายเดือนก่อน

      Can you not use generics for that, ie. List ? I do something similar for caching. But using generics , then you can also restrict the list to be classes inherited from your Entity base object.

    • @MarvinKleinMusic
      @MarvinKleinMusic 8 หลายเดือนก่อน

      @@Biker322 there is no entity base model. Just 10 different classes which are all stored in one list.

  • @davestorm6718
    @davestorm6718 7 หลายเดือนก่อน

    The only time I had to use list of objects was for integrating with a crappy api (for a specific accounting program).

  • @saberint
    @saberint 8 หลายเดือนก่อน

    Hmm we use a dictionary because the value could be almost anything (int, float, string, datetime etc)

  • @nicholaspreston9586
    @nicholaspreston9586 7 หลายเดือนก่อน

    Thanks for pointing out that LinkedIn is a bad place for .NET tips. I see a bunch of Indian devs putting out a bunch of syntactical patterns that either don't have an effect on anything or a just straight-up anti patterns. Very few developers, namely Sr. developers, put anything worthwhile out (like ways to implement the vertical slice architecture), and even they can be wrong.
    It's good to see someone set the record straight, because frankly, I sometimes get peeved at the amount of stupidity in some of the C# I read online. C# is not complicated, but so many devs overcomplicate it thanks to the cancer that is Object Oriented Programming.

  • @andraslacatos5832
    @andraslacatos5832 8 หลายเดือนก่อน

    Hi Nick, are you planning to drop a promo code on the microservices deep dive course? Already have the getting started course and looking forward to get the deep dive as well

  • @mehdizeynalov1062
    @mehdizeynalov1062 7 หลายเดือนก่อน

    I think the reason they included List that wanted to sum the count to 10 as per heading. nonsense - didn't need to spend this much time on that issue.

  • @killerwife
    @killerwife 7 หลายเดือนก่อน

    List of objects - json parsing - when I need to do some weird shenanigans with inconsistent content

  • @dotnetforever
    @dotnetforever 8 หลายเดือนก่อน +14

    List - never. For 15 years.

    • @milendenev4935
      @milendenev4935 8 หลายเดือนก่อน +4

      same but for 10

    • @johnnyblue4799
      @johnnyblue4799 8 หลายเดือนก่อน +1

      I'll do it once, to see how my colleagues will react! :)))

    • @dotnetforever
      @dotnetforever 8 หลายเดือนก่อน

      XD))

    • @milendenev4935
      @milendenev4935 8 หลายเดือนก่อน +1

      @@johnnyblue4799 might die, just saying

    • @johnnyblue4799
      @johnnyblue4799 8 หลายเดือนก่อน

      @@milendenev4935

  • @fusedqyou
    @fusedqyou 8 หลายเดือนก่อน

    `List` is completely pointless considering most collection types have a non-generic variants that does exactly this.

  • @CharlesCooperGetsItDone
    @CharlesCooperGetsItDone 6 หลายเดือนก่อน

    I recognize these bad tips, the writer took a common list of tips for older versions of .NET from 2005 and tried to do a 1 for 1 update for today. Instead of coming up with new tips they took the 2005 list and they updated each tip individually.

  • @filiecs3
    @filiecs3 8 หลายเดือนก่อน

    I actually have seen people use List when they don't need to. Typically JavaScript programmers trying to learn C#.

  • @EdRawrDev5813
    @EdRawrDev5813 7 หลายเดือนก่อน

    I do have some thing like this to get generic objects from a FiB db , any advice would be deeply appreciated
    '
    public async Task GetChilds(string concept)
    {
    if (fibClient != null)
    {
    var concepts = await fibClient.Child($"{concept}").OnceAsync();
    return concepts;
    }
    return null;
    }
    '
    I set the concept name of the table and if there is something it will return

  • @Kegwen
    @Kegwen 7 หลายเดือนก่อน

    I don't know that I've ever wanted or needed the object "type" in my entire life

  •  หลายเดือนก่อน

    11:08 Acts 12:22-23

  • @drugged_monkey
    @drugged_monkey 8 หลายเดือนก่อน +1

    I'm in C# nearly 12 years and I never seen List even in worst possible pieces of code. Yes, I meet object[] sometimes but mostly in code related to really dark ages of .Net Framework 1.1/2

  • @MasoudKazemiBidhandi
    @MasoudKazemiBidhandi 7 หลายเดือนก่อน

    It is sad to see some people start to give advice to others and cant give out the example for it. for the Exception part, in some source code you see that there are cases that coder throw Exception in his/her code just to break the execution and return immediately back to caller. this kind of coding is not desirable and should be avoided if possible. so its not even about placing Try, Catch, Finally in codes which is perfectly fine.

  • @winchester2581
    @winchester2581 7 หลายเดือนก่อน

    ArrayList really gives me those flashbacks from Java

  • @TheDiggidee
    @TheDiggidee 8 หลายเดือนก่อน

    Currently stuck in the async/await argument with someone. It's not fun

  • @ProSunnySharma
    @ProSunnySharma 7 หลายเดือนก่อน +1

    I find the title misleading. It's like stop eating to cure your body!! Later the vide says - use async/await judiciously!

    • @berkanbilgin2287
      @berkanbilgin2287 7 หลายเดือนก่อน +3

      Thats typical with his video thumbnails and contents. Classic click bait he keeps doing. This guy becoming annoying to me recently

  • @veec1539
    @veec1539 8 หลายเดือนก่อน

    Just got assigned a side project with a few devs. No c# experience, their code is littered with var, dynamic, and object.... Unfortunately they wore something a VP wanted so my hands are tied....

  • @jfftck
    @jfftck 8 หลายเดือนก่อน

    I like how it is bad advice to do List, but that is what JavaScript arrays are and it is ranked higher than C#. So, using them in C# should still be faster than all JavaScript arrays, but it is always preferable to use an exact type in all instances for multiple reasons: type safety, performance, memory usage, etc…

  • @AvenDonn
    @AvenDonn 8 หลายเดือนก่อน +3

    I used a list of objects because it legitimately had to store any value in it to be consumed by something else that would perform some kind of logic on the value.
    It was the easiest way at the time, performance wasn't important and re-architecting the code would take weeks
    Working with enterprise software legacy code sure does pay the bills and I'm not paid by the line of code

    • @lordmetzgermeister
      @lordmetzgermeister 8 หลายเดือนก่อน

      I would've made a class with a property inside and instead of list.Add(value) it would be list.Add(new() { Prop = value }), which is mildly less headache-inducing and easier to modify/expand in the future.

    • @AvenDonn
      @AvenDonn 8 หลายเดือนก่อน

      @@lordmetzgermeister oh and what would be the type of that Prop? Might it be object?

    • @okmarshall
      @okmarshall 8 หลายเดือนก่อน

      @@AvenDonn Yes, but the benefit is you can add other properties to that class that contain other information.

    • @AvenDonn
      @AvenDonn 8 หลายเดือนก่อน

      @@okmarshall okay, sure, but that's beyond the scope of the original suggestion. The problem didn't need it

  • @AdamMayer-uf6nd
    @AdamMayer-uf6nd 2 หลายเดือนก่อน

    Your advice on using try / catch is not really correct. The correct best practice is "Only catch exceptions you actually handle. Logging an exception is not handling it." In general, you should let your exceptions flow up to a global exception handler. If you use a try block and catch the ex, you may want to enrich the exception with some local diagnostic info, but you should throw or throw a new ex containing the original ex. You should not let your code continue to run just because you have a catch block and you log the ex! Let your app fail and fix the code that is causing the exception. This is called "fail fast" and over a fairly short period of time it has the effect of hardening your your code. Another shorter way of saying this is: Don't swallow exceptions and keep running. If your code throws and it is not something you know you can handle, let your app crash and fix the problem. There are a lot of developers who don't understand this - your videos are great you should cover Fail Fast in-depth.

  • @ernstgreiner5927
    @ernstgreiner5927 8 หลายเดือนก่อน

    These Code Cop videos are really horror. I recommend „Nightmare on Elm Street“ or something else as starter to get used to it…

  • @nikize
    @nikize 7 หลายเดือนก่อน

    13:20 seriously use using!! Dispose should always close things correctly, you seem to be claiming that it doesn't do close, it does, and not only that, you should always return resources, even if exceptions happens.
    Please don't spread bad practices!