Cleaner C# code with "smart" using statements

Поделиться
HTML-код
  • Опубликовано: 6 ноя 2024
  • Check out my Dependency Injection course: dometrain.com/...
    Use discount code YTDEP1 at checkout for 15% off
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I will show you how to use the using statement in C# in a different way in order to write cleaner C# code in .NET.
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasG...
    Follow me on Twitter: bit.ly/ChapsasT...
    Connect on LinkedIn: bit.ly/ChapsasL...
    Keep coding merch: keepcoding.shop
    #csharp #dotnet

Комментарии • 151

  • @dgschrei
    @dgschrei 2 года назад +149

    We have pretty much exactly this class in our code base. And while I don't mind it for that particular use case, I'd be careful in introducing that in other parts of the code.
    Mainly because it is already hard enough to get junior devs to understand that the garbage collector is not magic and that to prevent memory "leaks" IDisposable is a thing and needs to be looked out for and adhered to.
    And having a ton of classes that all implement IDisposable even though they don't actually dispose of any resources just makes it more likely that people will stop checking for IDisposable (or ignore IDE hints about a missing Dispose) and therefore miss the cases where it is absolutely necessary to call Dispose and then you're left diagnosing why your application ballooned to gigabytes in size on the customer's machine.
    So technically a nice trick but since it is a misuse of the Dispose pattern, it should be used very sparingly for the kinds of classes where you'd need to litter half the code base with finally blocks without it.

    • @weslleyalcoba
      @weslleyalcoba 2 года назад +3

      Another quirk of being a "misuse", is that framework upgrades doesn't have to comply to it or even mark the use as deprecated for future removal. Meaning, if the community decides to change how it works, you can have massive problems upgrading to new versions. Chances are small, but they do exist. Still a very fun trick though. I have to admit.

    • @pentanoir
      @pentanoir 2 года назад +1

      Great comment, I learned from it!
      Cool technique in some cases though, hadn't considered this usage.

    • @majdps995
      @majdps995 2 года назад +5

      I was looking for this exact point of view in the comment section and was surprised it's the first comment. That's exactly what I thought about. A nice trick but not a nice choice.

    • @anarkisgaming
      @anarkisgaming 2 года назад +2

      So much this. As much as it's kind of a nice party trick, it's really a bad idea long term to implement it that way.

    • @istovall2624
      @istovall2624 2 года назад +4

      Ive been on teams where the mindset was, "dont let the jr devs break anything" by using restrictions or dumbing down things. And on teams where, "if the jr devs break something they own fixing it".
      I beleive the first is better for financially critical systems like commercial software or literal financial software, and the later is better for inhouse supported and built software, like custom ms excel upload UIs to be processed by commercial software.

  • @davidwilliss5555
    @davidwilliss5555 2 года назад +10

    I like this. We used to do something similar in C++ using the destructor at a job I had about 15 years ago. In C++, you can declare a local instance of a class without using the new keyword and it allocates it using stack memory and automatically disposes when the variable goes out of scope. We definitely used it for timing operations like this. I seem to recall we also used it to acquire and release a lock or something because C++ didn't have the lock keyword.

  • @marcusmajarra
    @marcusmajarra 2 года назад +11

    IDisposable + using brings to the table the equivalent of C++ destructors. In other words, you get the ability to guarantee that a block of code will automatically get executed when a variable falls out of scope, without having to clutter the code with more elaborate bootstrapping that distracts from the responsibility of the unit of code that you're writing. And while this is an incredibly powerful tool to have around, it comes with the caveat that in both cases, these mechanisms were designed with the intent to prevent human error regarding freeing up resources acquired by the object in question. You're not supposed to be doing anything other than releasing resources in this automatically executed code.
    That being said, this design intent is something I tend to abandon very quickly in all my projects. Rather than limiting IDisposable implementations to classes that free resources, I instead consider IDisposable implementations as classes that delegate code execution on object disposal by design because this is the feature that the language actually provides. I can use this in principle to free acquired resources, but also to run an arbitrary unit of code that might be interesting to have.
    Is this a problem for me? No, because I always check for IDisposable implementations. It doesn't matter how IDisposable is implemented in any given class because the intent is always the same: when the object is no longer necessary, it should be disposed. How this disposal manifests itself should not be a concern of the code that uses the disposable object in the first place. As such, it doesn't matter if Dispose actually releases resources because I would still look to ensure it gets called in client code.

  • @distinguishedmoments2277
    @distinguishedmoments2277 2 года назад +9

    Thanks again Nick, I truly love your curiosity and the fact that you are sharing.
    It's inspiring to watch someone who enjoys his work. My Man

  • @fedefex1
    @fedefex1 2 года назад +8

    The same can be done to create a sort of lock declaration. Just decompose the lock keyword to monitor.enter() and monitor.exit(). Or even with SemaphoreSlim with IAsyncDisposable. For example: await using var _ = _ss.WaitAsyncScoped();
    Or using var _ = _locker.LockScoped()

  • @ivandrofly
    @ivandrofly 2 года назад +1

    I know c# to the core, but I still enjoy watching you videos :)

  • @junellawrencecordova6761
    @junellawrencecordova6761 2 года назад

    That's really cool! I never knew `using` worked that way. Love how you deep dived into it and actually showed what happens under the hood.

  • @root317
    @root317 2 года назад +16

    9:22 gets me every time. 😂😂😂😂

  • @Taal111
    @Taal111 2 года назад

    An elegant way of leveraging the using statement mechanics, thanks!

  • @sergiuszzalewski1947
    @sergiuszzalewski1947 2 года назад +5

    Yeah so it is some kind of defer in Go. You can make it generic and pass any delegate to be executed. There is a good article about this called "Defer with C# 8.0"

  • @gregorylouppe1624
    @gregorylouppe1624 2 года назад +12

    It’s so smart and tricky at the same time… I wouldn’t mind having something similar in a closed package.
    Why closed? Because of the confusion it brings to the table.
    When Dispose() is not disposing anything, then it’s not supposed to be named like this.
    On the other hand, it’s so clean… maybe having a forwarding layer over IDisposable would be less confusing (also giving the opportunity to document this abuse of IDispoable were I think is relevant)

    • @nickchapsas
      @nickchapsas  2 года назад +5

      I recommend using it in library code only since you can easily hide it and no one will ever know. In main project code, developers that don’t know how this works will be lost

    • @benjaminclehmann
      @benjaminclehmann 2 года назад +1

      You can use the destructor instead and I think that's less confusing and avoids hijacking IDisposable. This will be familiar to you if you come from C++.

    • @clementdurazzo4774
      @clementdurazzo4774 2 года назад +6

      Except that you can’t really decide when the destructor is called. It’s used by the garbage collector and you can’t explicitly call it so your measurement will be wrong most of the time.

    • @PlerbyMcFlerb
      @PlerbyMcFlerb 2 года назад +2

      IMO it's a perfectly legit use-case. I think it's a little infantilizing of one's fellow devs to think that they wouldn't be able to grok it.
      It also comes with the added benefit that the team will end up understanding disposables/usings a little better as a result.

    • @phizc
      @phizc 2 года назад

      You can have an explicit IDisposable.Dispose() method and return the TimingLogger from the extension method. It'll still show up as IDisposable so "using" works, but you have to cast it to IDisposable to call Dispose manually.

  • @clementdurazzo4774
    @clementdurazzo4774 2 года назад

    That’s exactly the pattern used for MiniProfiler ! It’s a good example of production ready use of the concept explained here

  • @ibrahimhussain3248
    @ibrahimhussain3248 2 года назад

    never thought of using "using" like that. Love it :)

  • @zariumsheridan3488
    @zariumsheridan3488 2 года назад

    I recently used a similar approach. But instead of ILogger etc, I pass an Action to the constructor, which is then called when this "handle" leaves the scope. Basically using C# language constructs to mimic C++ RAII.

  • @vanjazed7021
    @vanjazed7021 2 года назад +4

    This looks like RAII from C++/Rust. Very nice and clean way of doing things at the end of the scope.

    • @DhanarAdiDewandaru
      @DhanarAdiDewandaru 2 года назад +1

      Well I do not know about C++ but this C# "using" has existed even before Rust was invented AFAIK.

    • @zariumsheridan3488
      @zariumsheridan3488 2 года назад +1

      @@DhanarAdiDewandaru it's been used in C++ even since before C# existed en.wikipedia.org/wiki/Resource_acquisition_is_initialization

  • @morganskinner3863
    @morganskinner3863 2 года назад +2

    I’ve also used this when setting and resetting the Windows cursor in WinForms back in the day, must have been using this for 20 years now, given that I started using C# in 2001. Pun intended. 😀

    • @JoeBonez
      @JoeBonez 2 года назад

      Same, only in WPF rather than Winforms

  • @Palladin007
    @Palladin007 2 года назад +3

    I would use readonly structs (with IDisposable) for those situations
    Or a readonly ref struct, but that cannot be used with await.

    • @phizc
      @phizc 2 года назад

      ref struct can't have interfaces so you need to use duck-typing. It'll just make it more confusing. Readonly struct is what I do.

  • @nerminsehic4542
    @nerminsehic4542 2 года назад

    I wish there was a channel like yours for the Java community :/

  • @williamliu8985
    @williamliu8985 2 года назад

    interesting usage for using! btw, I like the 6_9 eyes...

  • @nooftube2541
    @nooftube2541 2 года назад

    Don’t interpolate messages for loggers. they are usually cached, interpolation would degrade performance, and remove ability to properly sort messages. Just add ms to args array.

    • @nickchapsas
      @nickchapsas  2 года назад +2

      Not in the default logger but what you are saying is valid if you are using Serilog

    • @nooftube2541
      @nooftube2541 2 года назад

      @@nickchapsas you never now how logger utilized, the default logger can use serilog inside, or it could put messages into msmq where message template would matter. Anyway "it depends", and string interpolation would work correctly only in some situations and in another it would bring problems.

  • @MichaelBattaglia
    @MichaelBattaglia Год назад

    Very clever trick!!

  • @peymannaji
    @peymannaji 2 года назад

    Hi Nick! Thanks for the video. It is very helpful.
    Since you are a Rider user, Could you please provide a video for us and explain the cool features of Rider + Extensions or configuration etc that you use?
    Thanks!

  • @lordchutney9000
    @lordchutney9000 2 года назад +1

    Have seen this and similar patterns for gathering ephemeral metrics in the wild. It’s good… but… beware nesting! Actions in the dispose can start to impact other metrics being gathered and give you false readings,

  • @yunietpiloto4425
    @yunietpiloto4425 2 года назад

    Very nice as always

  • @vkouvelis
    @vkouvelis Год назад

    Χαιρετίσματα από έναν παλιό του MXC :D

  • @nietschecrossout550
    @nietschecrossout550 2 года назад +1

    As always use a struct for anything that doesn't need to be moved to the heap. In this case you could even get away with a readonly ref struct and implicit dispose pattern implementation...

    • @Palladin007
      @Palladin007 2 года назад +3

      A readonly ref struct cannot be used with await.
      Just use a normal struct and implement IDisposable.
      There will be no boxing either.

  • @yendisgomes2831
    @yendisgomes2831 2 года назад +1

    amazing!
    Could you create an example about best way for writing file in multi task and large file >= 70mb?

  • @vinodsharma-ok1mv
    @vinodsharma-ok1mv 2 года назад

    Thank you Nick for clean code

  • @Tsunami14
    @Tsunami14 2 года назад +2

    Very interesting for you to bring this up. There's certainly been times I've though up similar creative uses for using / Dispose(), but always steered away because it felt like a code smell (or at the very least, a hack) since it breaks the assumption of cleaning up unmanaged resources.

    • @nickchapsas
      @nickchapsas  2 года назад +1

      As long as you do it in library code, you are fine. Library code has internal code anyway so you aren’t hiding something that shouldn’t already be hidden

  • @beses4530
    @beses4530 2 года назад

    What a nice concept, thanks for the vid!

  • @xxdeadmonkxx
    @xxdeadmonkxx 2 года назад

    Using that to do push/pop debug group in OpenGL for nested profiler markers

  • @MsKpg
    @MsKpg 2 года назад

    Hey great video! Btw what is the tool you use to highlight with red color box and draw etc?

  •  2 года назад

    Nice. Should probably add something like 'if(_logger.IsEnabled(_logLevel))', since the '_message' can be formatted with the '_args'?

    • @nickchapsas
      @nickchapsas  2 года назад +2

      Yeah he whole IsEnabled thing is actually a topic I have for a video coming in mid January, but yeah you are right

  • @DevLife717
    @DevLife717 2 года назад +1

    What’s the deal with the eyes overlay at the 9:22 mark?

  • @F1nalspace
    @F1nalspace Год назад

    I wrote exactly that in my profiler library two years ago and it worked beutifully - but often i need that in a specific scope, so i prefer to use the old way -> using (...) {} instead. But nowadays we dont use that anymore and fully removed all the profiling code. Profiling is only done with BenchmarkDotNet now - which is fine, but i would have prefered to leave the profiling code in, so i can manual profile specific codes if needed and get metrics such as CPU-Cycles - which you wont get with benchmark-dot-net.

  • @qchaudhry1
    @qchaudhry1 2 года назад

    Very clever.

  • @vgg6273
    @vgg6273 2 года назад

    Is there any nice way to avoid writing try catch block on every method and still catch the exception message(Local exception message not the global exception message)?

  • @parkersmith3727
    @parkersmith3727 2 года назад

    This is great

  • @JohanNordberg
    @JohanNordberg 2 года назад

    Very clever and clean.

  • @istovall2624
    @istovall2624 2 года назад

    Love it!

  • @clearlyunwell
    @clearlyunwell 2 года назад +1

    9:01 this is where the fun starts 😋

  • @BenRogersWPG
    @BenRogersWPG 2 года назад

    Awesome video.

  • @abhishekbagchi6052
    @abhishekbagchi6052 2 года назад

    Brilliant video

  • @mikhail_kulkov
    @mikhail_kulkov 2 года назад

    Yeah but this kind of profiler has a scope. Imagine if you want to measure your first call "var weather = await ..." and then use var weather after the measuring ends. In such case you have to declare var weather before "using" statement. And depending on part of code you want to profile it can be many more vars which you have to declare previously. So the code still may be pretty clunky.

  • @Rob_III
    @Rob_III 2 года назад +3

    Wouldn't the compiler (maybe in the future) be able to determine WHEN something goes out of scope and dispose "too early"? Your discard variable, technically, goes out of scope immediately since it's not used anywhere else. I thought about this earlier and think that's why I prefer the "old" using syntax where the scope is very explicit using the curly brackets (accolades). I think this is prone to optimizations done by the (future?) compiler.

    • @nickchapsas
      @nickchapsas  2 года назад +3

      If they did that they would break 100% of existing code so no they won’t do that. Using’s purpose is clear. Replace try finally and a dispose call, with using. Any change to that breaks everything

    • @Rob_III
      @Rob_III 2 года назад

      ​@@nickchapsasI've tried to demonstrate it here: dotnetfiddle id JQiIFd
      Using the new syntax the compiler MAY be able to determine (in the future?) when an object goes out of scope. Correct me if I'm wrong. The documentation on the using statement says:
      "The newer using statement syntax translates to similar code. The try block opens where the variable is declared. The finally block is added at the close of the enclosing block, typically at the end of a method."
      Note the "*typically* at the end of a method". No guarantees that I can see?

    • @Rob_III
      @Rob_III 2 года назад

      @@cassiel6666 Hmm, "The finally block is added at the close of the enclosing block" makes sense and, indeed, sounds more like a guarantee. Bit of a shame though, I can see situations where disposing earlier could be beneficial. Then again, using the "old" syntax should solve that. Cool. Thanks for pointing it out!

  • @cn-ml
    @cn-ml 2 года назад

    9:22 Nice.

  • @jmschuaquico
    @jmschuaquico 2 года назад

    Very interesting! I don't think I would use it for production tho. Other programmers would hate me 🤣

    • @clementdurazzo4774
      @clementdurazzo4774 2 года назад

      It’s used every single day by… stack overflow 😜

  • @briansepolen4917
    @briansepolen4917 2 года назад

    At 7:40, you mention a website, i don't see it in the description of the video... What is the website?

  • @TheCodingColtrane
    @TheCodingColtrane 2 года назад

    I still don't get why should i use a delegate and an interface. Any advices ?

  • @axelbreekweg
    @axelbreekweg 2 года назад +3

    Cheeky 9:22

    • @paulkoopmans4620
      @paulkoopmans4620 2 года назад

      one possible improvement though; a better place for this overlay would have been 4:20 don't you think? :)

  • @_CazaBobos
    @_CazaBobos 2 года назад

    3:45 what's the reason of placing a string like that instead of just using string interpolation?

    • @nickchapsas
      @nickchapsas  2 года назад

      Because of structured logging

    • @_CazaBobos
      @_CazaBobos 2 года назад

      @@nickchapsas would you mind telling me the technical name for that kind of string presentation? I'd like to investigate it.

    • @nickchapsas
      @nickchapsas  2 года назад

      @@_CazaBobos The technical name is "structured logging". Here is an in-depth explanation: ruclips.net/video/6zoMd_FwSwQ/видео.html

  • @paulbaker78
    @paulbaker78 2 года назад

    I love it in theory, but I'm worried that I'd lose the less senior devs working with me.

  • @arunbm123
    @arunbm123 Год назад

    Your courses are listed on udemy?

  • @evanboltsis
    @evanboltsis 2 года назад

    Thanks for the info.
    P.S.: fix the description of the video :)

    • @nickchapsas
      @nickchapsas  2 года назад

      What’s wrong with the description?

    • @evanboltsis
      @evanboltsis 2 года назад

      @@nickchapsas injeciton --> injection

    • @nickchapsas
      @nickchapsas  2 года назад

      @@evanboltsis Nice one thanks

  • @jackkendall6420
    @jackkendall6420 2 года назад

    clever, very clever!

  • @figloalds
    @figloalds 2 года назад

    This is similar to python concept of "context manager"

  • @jamesevans2507
    @jamesevans2507 2 года назад +2

    Video starts at 09:10 if you already know what the using statement is

  • @anthonylerouge9900
    @anthonylerouge9900 2 года назад

    using string interpolation with logger is a warning in .net 6.
    What do you think about that ?

    • @nickchapsas
      @nickchapsas  2 года назад

      Because it lead to memory problems. Strings are immutable so any string combination will be allocated as a new string. That was always a problem and especially with serilog it would also hide any property captures

  • @possessedllama
    @possessedllama 2 года назад

    I don't know how I feel about using IDisposable like this.

  • @DaminGamerMC
    @DaminGamerMC 2 года назад

    what is the try{} finally{} even doing why not just call the Dispose method anywhere

  • @DrWambua
    @DrWambua 2 года назад

    awesome.

  • @axelbreekweg
    @axelbreekweg 2 года назад

    At 10:40 you chose to use a field _args as type 'object?[]' but aren't they nullable by default?

    • @nickchapsas
      @nickchapsas  2 года назад +1

      Not in my project where I have null reference types enabled

  • @barmetler
    @barmetler 2 года назад +1

    Ayo why does your top bar in rider look different to mine? Some kind of plugin?

    • @nickchapsas
      @nickchapsas  2 года назад

      I’m probably on the latest version

    • @barmetler
      @barmetler 2 года назад

      @@nickchapsas I'm using the eap version (edit: 2021.3.1 is now released, so no longer eap). And the 2020 version. Both of them don't look like this. Maybe it's a setting that you have?

    • @restveggie6155
      @restveggie6155 2 года назад +1

      @@barmetler View -> Appearance -> then, select Toolbar instead of Toolbar Classic. Always take about 10 minutes to read “what’s new” every time new version released. 😂

    • @barmetler
      @barmetler 2 года назад

      @@restveggie6155 Ah I was looking through the settings, that's why I was confused. And also, I don't have rider for that long, so I haven't gotten to see every "what's new"!
      Also, I'm supposed to read? That sounds like work, ngl XD
      But thanks, it looks really good!

  • @OeHomestead
    @OeHomestead 2 года назад

    Unless you use a using scope { ... }, you may end up timing stuff you do not want to time :-)

  • @Sebastian----
    @Sebastian---- 2 года назад +2

    I think this a bad example of using.
    Using should be only be used for release resources and there are better way for logging.
    Generic intercepters, decorators or logger with a method like " Task Log(Task actionToLog)"

    • @nickchapsas
      @nickchapsas  2 года назад

      I explained in the video that even though what toured suggesting looks reasonable, it will almost certainly have closure issues.

  • @RichardONeil
    @RichardONeil 2 года назад

    Nice! :P

  • @hanaasihanish
    @hanaasihanish 2 года назад

    How you are navigating to source code?

    • @nickchapsas
      @nickchapsas  2 года назад

      I am using JetBrains Rider as my IDE and it supports that feature

    • @clementdurazzo4774
      @clementdurazzo4774 2 года назад

      JetBrain resharper vs extension could do it also if you need to.

  • @LilPozzer
    @LilPozzer 2 года назад +1

    Nick: don't even try

  • @Bliss467
    @Bliss467 Год назад

    Feels hacky. Hidden behavior. Clever tho!

  • @saintinel
    @saintinel 2 года назад

    Dmn smart indeed... :p

  • @samplebug
    @samplebug 2 года назад

    Name it "From Zero to Hero: Dependency Injection in .NET CORE with C#"

    • @nickchapsas
      @nickchapsas  2 года назад

      It's not .NET Core. It's .NET

    • @samplebug
      @samplebug 2 года назад

      Sorry, I might have gotten confused. From introduction, in seemed like the course excludes .NET framework, includes only .NET Core 1.0 to 1.6.

  • @MichaelBeck_profile
    @MichaelBeck_profile Год назад

    This feels so dirty :D

  • @4eJIeHTaHo
    @4eJIeHTaHo Год назад

    That's on-targeted use of 'IDisposable', you don't release any resources thus you violate single responsibily principle.

  • @MichaelNikolaus
    @MichaelNikolaus 2 года назад

    This is so funny, while I‘m watching this Video I‘m currently implementing exactly this…

  • @clearlyunwell
    @clearlyunwell 2 года назад

    👍🏽

  • @mvanderseijs
    @mvanderseijs 2 года назад

    At ruclips.net/video/iqt7bqAm27U/видео.html, can't you just make it even shorter by discarding the return var and simply write
    using (logger.TimedOperation(nameof(GetCurrentWeather)))
    {
    ...
    }
    ?

  • @tulliandar
    @tulliandar 2 года назад

    Lol @ the 69 joke 😂

  • @MMMM-vc5oi
    @MMMM-vc5oi 2 года назад

    Perfect but I do not like that, hiding behaviour

    • @nickchapsas
      @nickchapsas  2 года назад

      It is ok to hide behaviour in library code. This shouldn’t be used in main project code. However most of the libraries you are using, do this and you just don’t know about it

    • @PlerbyMcFlerb
      @PlerbyMcFlerb 2 года назад

      Another word for hiding behavior is "encapsulation" ;-)

    • @MMMM-vc5oi
      @MMMM-vc5oi 2 года назад

      @@PlerbyMcFlerb I suggest you to learn more about encapsulation

    • @MMMM-vc5oi
      @MMMM-vc5oi 2 года назад

      When you want to call a method of a class (instance), it should be clear without any side effects.
      Here, when you call that method with ugly using, you should know it stops the watch at the end of the block. Also, this approach depends on .Net C# version
      I see it like goto. You can apply "goto" every where but should apply?
      The purpose of using "Dispose" and "using" is clear, disposing resources automatically when exiting that block.
      Because you can do, it does not mean it is perfect and the best choice!
      I prefer other approaches, this approach is not related to encapsulation at all
      As Nick mentioned, it is OK for tools, frameworks and libs with documentation

    • @MMMM-vc5oi
      @MMMM-vc5oi 2 года назад

      One approach
      private void Main(){
      _logger.TimedOperation("message",
      ()=>
      {
      //...
      } );
      }
      public static void TimedOperation(this ILogger logger,string message,Action action)
      {
      StopWatch sw=new StopWatch();
      sw.Start();
      action.Invoke();
      sw.Stop();
      // log
      }

  • @JakeAndDaddy
    @JakeAndDaddy 2 года назад +6

    Just because you can, it doesn’t mean you should.
    Dispose should release resources. Nothing more.

    • @nickchapsas
      @nickchapsas  2 года назад +7

      Why? Btw this is exactly how Serilog, the biggest logging framework, is doing timed operations

    • @Sebastian----
      @Sebastian---- 2 года назад +3

      @@allannielsen4752
      Your code should show your intention.
      Dispose shows your intention to release some locked resource. You are "lying" to the reader of the code or atleast your code don`t present your intention.
      Is like making your confirm button in red. Mixed message are bad for the understanding.

    • @vanjazed7021
      @vanjazed7021 2 года назад +1

      This is very similar to RAII approach in C++ and Rust that uses destructors/drop to do actions on scope end, not just resource management, despite the name. It was proven there that this approach is perfectly valid for things like this

    • @BittermanAndy
      @BittermanAndy 2 года назад

      C++ and C# are not the same. What is idiomatic in one may be surprising and dubious in another. I've spent more years than I care to think about cleaning up C# codebases that was butchered by people who knew C++ but never bothered learning the difference when they changed language.
      As just one example, a destructor in C++ always happens as soon as the object goes out of scope, so you just need to create the object and you know it will work. RAII FTW!
      The Dispose method in C# is not a destructor. It must be called (perhaps explicitly, or perhaps implicitly by using). Forget to add the using statement when you create the object shown in the video? Dispose won't be called. But what if the class has a finalizer? Dispose might be called... at some point... in some future garbage collection, which could be literally hours after the object went out of scope, in a completely different part of the code, on a whole different thread.
      Does that sound like the kind of bug you want to investigate? Not me. And there are other problems with it too.
      Exactly as the other commenters said: using/Dispose in C# has a very specific meaning that C# programmers know and expect. Breaking that meaning is dangerous. Please don't do it, unless you have a *very* good reason, and then add appropriate tests plus comments explaining why you're breaking the rules (which you obviously won't do for a technique that's supposed to cut down on cruft, so won't happen).

    • @agsystems8220
      @agsystems8220 2 года назад +1

      The complaint should be that IDisposable is not an alias for something like "IPromptFinally" (don't search it, I just made it up), which we would want to use in this case. Use of a feature in a way not intended is definitely a whiffy hack, but this mostly smells because IDisposable is overly specific in it's implied use. It works fine as a more general IPromptFinally, with the specification being exactly what you would expect from such an interface.
      I do completely agree that "it's a minor hack that C# programmers get used to" is not a healthy thing to have in the language, but blame the language devs who put in a general feature with a specific name, rather than the user devs who have realised it is perfect for their use case despite the misleading name. We are not talking about undefined behaviour, or behaviour that can change without braking the expected use case. It does exactly what we want and always will.
      If it really bugs you you could actually alias it to a more appropriate name for the use case. The fact that it is just IDisposable under the hood shouldn't matter as much.

  • @LilPozzer
    @LilPozzer 2 года назад +1

    69?

  • @jamesherrero7334
    @jamesherrero7334 2 года назад

    sexy!

  • @artemyur7162
    @artemyur7162 2 года назад

    69 lol

  • @ngoroth_
    @ngoroth_ 2 года назад +1

    Hiding logic inside dispose it's wierd at least

    • @nickchapsas
      @nickchapsas  2 года назад +1

      You can do it in library code. It isn’t recommended to do it in main projects

  • @mAcCoLo666
    @mAcCoLo666 2 года назад

    Mh, so you are basically lying to the next guy by misimplementing IDisposable so you can save some indentation. Smart indeed.

    • @nickchapsas
      @nickchapsas  2 года назад

      If you've been using pretty much any popular .NET library then you've been using it too without even knowing

  • @keweiwang1449
    @keweiwang1449 2 года назад

    Hey guys, I would say this is not a good practice for such a scenario, here are the alternatives:
    1.use AOP if you want to log the time consuming for the api with correlation id
    2. if you want to control the scope, please try to use high order funtion to encapsulate the logic in this presentation, then warp your logic into lambda expression and pass into it

  • @alirezanet
    @alirezanet 2 года назад

    Smart... Nice!