Cleaner C# code with "smart" using statements

แชร์
ฝัง
  • เผยแพร่เมื่อ 22 ธ.ค. 2021
  • Check out my Dependency Injection course: dometrain.com/course/from-zer...
    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/ChapsasGitHub
    Follow me on Twitter: bit.ly/ChapsasTwitter
    Connect on LinkedIn: bit.ly/ChapsasLinkedIn
    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.

  • @root317
    @root317 2 ปีที่แล้ว +16

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

  • @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()

  • @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.

  • @Taal111
    @Taal111 2 ปีที่แล้ว

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

  • @ivandrofly
    @ivandrofly 2 ปีที่แล้ว +1

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

  • @beses4530
    @beses4530 2 ปีที่แล้ว

    What a nice concept, thanks for the vid!

  • @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"

  • @vinodsharma-ok1mv
    @vinodsharma-ok1mv 2 ปีที่แล้ว

    Thank you Nick for clean code

  • @ibrahimhussain3248
    @ibrahimhussain3248 2 ปีที่แล้ว

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

  • @JohanNordberg
    @JohanNordberg 2 ปีที่แล้ว

    Very clever and clean.

  • @yunietpiloto4425
    @yunietpiloto4425 2 ปีที่แล้ว

    Very nice as always

  • @abhishekbagchi6052
    @abhishekbagchi6052 2 ปีที่แล้ว

    Brilliant video

  • @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

  • @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.

  • @MichaelBattaglia
    @MichaelBattaglia ปีที่แล้ว

    Very clever trick!!

  • @istovall2624
    @istovall2624 2 ปีที่แล้ว

    Love it!

  • @BenRogersWPG
    @BenRogersWPG 2 ปีที่แล้ว

    Awesome video.

  • @williamliu8985
    @williamliu8985 2 ปีที่แล้ว

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

  • @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

  • @MsKpg
    @MsKpg 2 ปีที่แล้ว

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

  • @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!

  • @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

  • @jackkendall6420
    @jackkendall6420 2 ปีที่แล้ว

    clever, very clever!

  • @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.

  • @alirezanet
    @alirezanet 2 ปีที่แล้ว

    Smart... Nice!

  • @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

  • @xxdeadmonkxx
    @xxdeadmonkxx 2 ปีที่แล้ว

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

  • @parkersmith3727
    @parkersmith3727 ปีที่แล้ว

    This is great

  • @nerminsehic4542
    @nerminsehic4542 2 ปีที่แล้ว

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

  • @qchaudhry1
    @qchaudhry1 2 ปีที่แล้ว

    Very clever.

  • @clearlyunwell
    @clearlyunwell 2 ปีที่แล้ว +1

    9:01 this is where the fun starts 😋

  • @DrWambua
    @DrWambua 2 ปีที่แล้ว

    awesome.

  • @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,

  • @yendisgomes2831
    @yendisgomes2831 2 ปีที่แล้ว +1

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

  • @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.

  • @DevLife717
    @DevLife717 2 ปีที่แล้ว +1

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

  • @vkouvelis
    @vkouvelis ปีที่แล้ว

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

  •  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

  • @RichardONeil
    @RichardONeil 2 ปีที่แล้ว

    Nice! :P

  • @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 😜

  • @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)?

  • @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

  • @cn-ml
    @cn-ml 2 ปีที่แล้ว

    9:22 Nice.

  • @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

  • @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.

  • @paulbaker78
    @paulbaker78 2 ปีที่แล้ว

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

  • @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.

  • @TheCodingColtrane
    @TheCodingColtrane 2 ปีที่แล้ว

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

  • @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?

  • @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? :)

  • @clearlyunwell
    @clearlyunwell 2 ปีที่แล้ว

    👍🏽

  • @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!

  • @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!

  • @figloalds
    @figloalds 2 ปีที่แล้ว

    This is similar to python concept of "context manager"

  • @_CazaBobos
    @_CazaBobos ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  ปีที่แล้ว

      Because of structured logging

    • @_CazaBobos
      @_CazaBobos ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  ปีที่แล้ว

      @@_CazaBobos The technical name is "structured logging". Here is an in-depth explanation: th-cam.com/video/6zoMd_FwSwQ/w-d-xo.html

  • @arunbm123
    @arunbm123 ปีที่แล้ว

    Your courses are listed on udemy?

    • @nickchapsas
      @nickchapsas  ปีที่แล้ว

      No, only on Dometrain.com

  • @OeHomestead
    @OeHomestead 2 ปีที่แล้ว

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

  • @possessedllama
    @possessedllama ปีที่แล้ว

    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

  • @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

  • @tulliandar
    @tulliandar 2 ปีที่แล้ว

    Lol @ the 69 joke 😂

  • @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.

  • @saintinel
    @saintinel 2 ปีที่แล้ว

    Dmn smart indeed... :p

  • @mvanderseijs
    @mvanderseijs 2 ปีที่แล้ว

    At th-cam.com/video/iqt7bqAm27U/w-d-xo.html, can't you just make it even shorter by discarding the return var and simply write
    using (logger.TimedOperation(nameof(GetCurrentWeather)))
    {
    ...
    }
    ?

  • @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.

  • @MichaelNikolaus
    @MichaelNikolaus 2 ปีที่แล้ว

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

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

    This feels so dirty :D

  • @jamesevans2507
    @jamesevans2507 2 ปีที่แล้ว +2

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

  • @LilPozzer
    @LilPozzer 2 ปีที่แล้ว +1

    Nick: don't even try

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

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

  • @Bliss467
    @Bliss467 ปีที่แล้ว

    Feels hacky. Hidden behavior. Clever tho!

  • @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.

  • @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.

  • @jamesherrero7334
    @jamesherrero7334 ปีที่แล้ว

    sexy!

  • @artemyur7162
    @artemyur7162 2 ปีที่แล้ว

    69 lol

  • @LilPozzer
    @LilPozzer 2 ปีที่แล้ว +1

    69?

  • @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
      }

  • @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

  • @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.

  • @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