How C# 10 “fixed” string interpolation

แชร์
ฝัง
  • เผยแพร่เมื่อ 30 พ.ย. 2024

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

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

    I think it's important to point out that .NET 6 interpolated strings are now compiled to that new `ref struct` type that is implicitly cast to string. Realizing this made understanding this topic much easier for me. Other than that, thanks for the explanation!

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

    I have long saved development videos, but only the very best -- videos with content that is useful, interesting, high-quality, and not trivially found with a web search.
    I find that list has grown by nearly every video I have seen on your channel. Your to-the-point, in-depth, not-afraid-to-be-technical format and your passionate approach to real world challenges and solutions, acknowledging how awesome C# is but without the immature wall of isolationism developers often build around their favorite solutions, is prime-grade TH-cam content.

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

    Whoa, I haven't been following closely the more recent additions to C# since 10 but man... it's turning out to be one of my favorite updates. Just discovered InterpolatedStringHandlers (and your video) today but the mention of the CallerArgumentExpression is another jawdropping addition to me. That actually solves a problem I had for a feature I needed to implement. Looks like I'll need to go back and look through all the changes to see what else I'm missing.

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

    What I don't like about features like these is that they have no contract on declarations/definitions. They are not implementing an interface or extending a class, or using some sort of other way to ensure, that you're implementing such features correctly. The same is with async/await and GetAwaiter/Awaiter class, or the Deconstruct method. It's basically "convetion-based". Other than that, I love language features, which compile into something more, but still let you customize what it compiles into. It makes the code clean, more readable, but still optimized. I believe it's also possible to customize the async method builder, would love a video about that. Thanks for great content!

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

      This is a good point and unfortunately Microsoft has a good counter argument. The reason .NET doesn't use many interfaces for their classes is for backwards compatibility. They're afraid an interface change will break millions of lines of code that people have written and they weren't able to come up a good alternative solution at the time.

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

      @@briankarcher8338 Isn't this what default implementation for

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

    It's great to see how your voice and facials expressions change when you are showing something as cool as this. It makes feel the one listening to be excited about what you are showing too. Thanks for showing this level of enjoyment and keep up the good work.

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

    As clear as it ever could be! Great job, thank you!

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

    I'm curious if entity framework's latest iterations have applied this kind of optimization considering the massive amount of string building or interpolating involved in creating sql statements.

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

    This is some really insane (read: awesome) stuff. Thanks for showing.

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

    I have an implementation for logging ^^.
    You can pass a normal interpolated string to a log method and it will generate a state to create the message or provide all values for structured logging.
    The performance is not as good as generated logging (you explained it in your last video) and for a "real world" software I would still use the generated logging, but it's cool :D
    And it would be possible to create SQL statements in code with string interpolation and nobody can "forget" the parameters because the handler adds them automatically.

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

    Να ΄σαι καλά ρε Νικόλα για την γνώση που προσφέρεις!!!!!

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

    I love this, can see how this would be very beneficial for logging conditionally and enabling logging middlewares to determine if it should log or not instead of having to wrap the code in extensions etc

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

      You shouldn’t use string interpolation for logging. You’re going to lose the structured logging parameters and also when you end up logging for an active log level, it’s gonna use significantly more memory even with this efficient approach.

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

      ​@@nickchapsas Interpolated string handlers were actually designed with logging as one of the primary use cases. Adding CallerArgumentExpression to your AppendFormatted methods, you can preserve structured logging names. I have a (somewhat) working prototype for Serilog using this, but Serilog makes it a bit more complicated because of custom syntax for structure capturing operators (stringification and destructuring), but it's doable. In terms of memory, you can declare it as a ref struct (like DefaulteInterpolatedStringHandler) and basically avoid all (heap) allocations when logging is turned off :)

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

      @@nickchapsas I agree completely. I was referring to whether we log the whole string or just part of it for non structured logging where we log something regardless just amount/detail. Aldo where do you hear about these features?

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

      @@khellang The problem with CallerArgumentExpression is that is can capture ANY expression, so if in the place of a parameter you place a "DataTime.Now.ToString()" then good luck capturing that in structured logging. It's doable if absolutely everyone that's gonna touch the project is on the same page. The other problem with it is that even if you are to have a conditional shouldAppend check, and then instantiate a handler internally which is still a ref struct, you still actually allocate more memory than you need when logging is actually turned on. You can test that with the Debug.Assert example. When it doesn't fail it doesn't allocate any memory but when it does fail, then the AssertInterpolatedStringHandler ends up allocating more than before. You just can't beat source genned LoggerMessage.Define in performance.

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

    Well, now I wonder if you were to combine what you've shown us here with your logging optimization, would it actually be faster to use string interpolation? Either way, thanks for the video!

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

      You technically can, I was actually planning to show that as an example but the thing is that you don’t wanna do that because you wanna for structured logging to capture the variable consistently so in logging it’s still a bad practice

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

    Have you done a video on IO pipelines and/or channels? I had to use those recently and definitely would like to learn more about them. Thanks for the great vids!

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

    Thanks for explaining. Great that they fixed it!

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

    Though all that is saiud in the video here is technically correct, I think it is a very complicated and not very transparent way to achive the goal.
    I normally use a Func argument in cases, where I want/need to think about performance - run time here.
    I have inserted a short demo to present my case below (though TH-cam chat formatting isn't good for that).
    The time improvement in this case is above 99%, though I have not benchmarked memory consumption, so I have no idea if there is a difference here.
    using System;
    using System.Diagnostics;
    namespace StringConcatPerformance
    {
    class Program
    {
    ///
    /// Standard way to call method with string argument
    ///
    /// If false the message argument will not be used at all
    /// Represents some string, that it has taken some time to build
    public static void NormalMethod(bool showMessage, string message)
    {
    if (showMessage) Console.WriteLine(message);
    }
    ///
    /// Alternative way to call method with string-returning function argument
    ///
    /// If false the messageFunc argument will not be used at all
    /// A function, that, but only if showMessage argument is true, build and return a string value when called
    public static void FuncedMethod(bool showMessage, Func messageFunc)
    {
    if (showMessage) Console.WriteLine(messageFunc.Invoke());
    }


    static void Main(string[] args)
    {
    // Example of how to call "the old way" and as Func-argument
    NormalMethod(false, $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}");
    FuncedMethod(false, () => $"This string is created at {DateTime.Now:yyyyMMDD HHmmss.fff}");
    // Simple Stopwatch times benchmark test. Call both methods a lot of times but never actually use the Message/MessageFunc arguments
    var calls = 100000;
    var watch = new Stopwatch();
    watch.Reset();
    watch.Start();
    for (var i = 0; i < calls; i++)
    NormalMethod(false, $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}");
    watch.Stop();
    var normal = watch.ElapsedMilliseconds;

    watch.Reset();
    watch.Start();
    for (var i = 0; i < calls; i++)
    FuncedMethod(false, () => $"{i}'th call, {DateTime.Now:yyyyMMDD HHmmss.fff}");
    watch.Stop();
    var funced = watch.ElapsedMilliseconds;

    Console.WriteLine(@$"{calls} calls Normal: {normal} msec, Funced: {funced} msec");
    Console.WriteLine(@$"Difference: {(100 - 100.0 * funced/normal):N02}% saved with FuncedMethod");
    }
    }
    }

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

      Firstly, you should be using BenchmarkDotnet if you wanna get any reliable benchmark results. The problem with your code is the closures you create. It's not just about the speed but also, or even more, about the memory.

  • @xavier.xiques
    @xavier.xiques 2 ปีที่แล้ว

    Thanks again for your videos, Nick! You help me a lot.

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

    Damn, you are pretty knowledgeable.
    Only be careful with microbenchmarks, loop alignment is a big thing in this scenarios.
    Especially when comparing .net 5 (basically no loop alignment) and 6 (optimized loop alignment).
    In .net 5, changing the order of methods in the class can lead to different benchmark results.

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

    thanks for the great video!

  • @10HW
    @10HW 2 ปีที่แล้ว

    The only thing I know how to code is a window with an exit function in Visual Basic on Windows XP, this video was entertaining yet absolute gibberish.

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

    That seems like a lot of machinery to inline an if-statement... Kotlin has inline functions which inline lambda arguments as well. So:
    require(mybool){ "Failed!" }
    ... will accomplish the same as the message handler in C#. However, what really is nice in C# are the attributes to fetch the caller class name, caller method name and caller parameter expression. Simple and neat, I wish Kotlin had that.

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

      It's more than just inlining the if statement. You can also write custom handling for each type, for example in the case of string interpolcating a sql query. It can do way more things than this very basic example. I do like Kotlin's approach this this problem though. It just doesn't read as nice.

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

    Those method forwards are a great candidate for expression body over statement body 👀

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

      Yeap, I use statement body because of the folding. Expression body will get out of screen and be hard to show in the video, but you’re right, you would use expression body there

  • @asdasdasdasd-yd8ht
    @asdasdasdasd-yd8ht 2 ปีที่แล้ว +1

    Cool. Hey Nick, can you help me understand how you saved memory? Okay you did that for saving the space of string provided in method... but what about the extra space you allocated for your extra class?

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

      The EnsureInterpolatedHandler is a struct which only wraps the default C# handler struct.
      This wrapper only added behavior, not data, so no additional memory should be needed due to them being structs instead of classes (so no pointers to other heap-allocated objects).
      Please do correct me if I'm wrong though, would really love to dive deeper into this C# topic :D

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

      It's not about EnsureInterpolatedHandler being a ref struct but also about the AppendFormatted method using a generic which will prevent the boxing that happen with the string.Format method

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

    Does this affect String.Format in any way, or is String.Format (even more of a) legacy feature?

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

      AFAIK: string.Format is the same as it was before C#10. string.Format has already been making use of the ISpanFormattable interface before it was made public.

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

    Doesnt this completely change your recent logging video? Amazing stuff. Thanks for sharing

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

      No, the recent video is still more efficient than this because you don't allocate anything again no matter the log level.

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

    I think you should also show your viewers the ISpanFormattable interface and the memory implications of implementing it in classes and structs that are used in string interpolation

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

    Is there a similar extension for VS that shows what we see on 3:11

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

    Huh... I USED to think that I was a C#/.NET expert... LOL

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

    That's a lot of black magic and long names. I understand that ref struct can have interfaces but will be great to be able to have actual types.

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

    This code does however evaluate all the expressions in the message passed in. For example if you do:
    static bool flag = true;
    EnsureThan.IsTrue(1==1, $"blabla {() =>{
    flag = false;
    return "flag was set to false.";
    }});
    Assert.IsTrue(flag);
    Then this test would actually fail. I was playing around with it a little and I was able to get this test to work with something like:
    public void IsTrue(bool condition, [InterpolatedStringHandlerArgument("", "condition")] InterpolatedStringHandlerPositiveChecks handler)
    This has the sad downside of not working with static functions, so I had to use a singleton there.

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

      This is not correct. If the `out` parameter in the constructor is false after construction, no part of the interpolated string handler will be evaluated.

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

    Prefect

  • @Ajay-km8br
    @Ajay-km8br 2 ปีที่แล้ว

    Nick, After watching your channel for so long, the quality of others just does not cut it for me. Can you make a series on Golang? We all win. I’ll send you a six pack of beer.

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

    Άψογος!

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

    I’m new to C# and this level of programming. Where do you recommend I start so that I can understand what you mean when you refer to heap vs stack, references, class vs struct, etc. ?

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

      Check this video out: th-cam.com/video/jONSIhMST9E/w-d-xo.html

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

      What form of programming doesnt have references, stacks and heaps?

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

      @@briumphbimbles I mean that it’s never been a concern for me at my level of experience. You couldn’t deduce that or are you being pedantic?

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

      @@danielbocelli No not being pedantic just curious which language you have been using where you thought it wasnt a concern?

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

      @@briumphbimbles uhm, functional form of programming for example? :) I mean when were you worry about these things in a typescript or a python code last time? :D

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

    If I noticed correctly, the code that you’ve written in the EnsureInterpolatedStringHandler constructor was actually inlined into the caller. If so, does it make sense to make this type “ref struct” as it is not instantiated anyway?

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

      It wasn't inlined. The compiler took that and instantiated the ref struct appropriately, so it is instantiated.

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

      The "ref struct" guards against boxing the value into the heap. So, it is just a safeguard to ensure that the code in the handler will not box it, to ensure that no unwanted allocations will occur, so yes it makes sense to use a "ref struct".

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

    Hi. Great video as always!
    I wanted to ask you about a problem specific to programmers, but not code :) What chair are you using? If I'm not mistaken, the logo looks like Secretlab. Is it good for long day's work? I am considering some ergonomic chairs, but they tend to be very expensive and I don't think I should rush with such a big investment.
    I want to use something that will keep me healthy for years to come and am wondering how it's been treating you so far.
    Thank you for all the videos. I really enjoy learning about topics I never encounter on my job, really is a breathe of fresh air! Keep up the great work!

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

      It’s as good as gaming chairs get but to be honest, a used Aeron would probably be a better investment. Im very happy with it, especially with their new softer seat, but I would try before I buy

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

    Great video. Nick, a quick question about memory efficiency: are you using transient/scoped or singleton services and repositories?

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

      It depends on the backing library

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

      @@nickchapsas do you agree that services should be scoped unless they need a state insde? The author of MediatR says that we need to do so and the extra object allocation is miserable

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

      @@antonmartyniuk It really, heavily depends on your dependencies. I don't use MediatR in high-perf situations anyway so it doesn't matter.

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

    Hello Nick, nice video again. Can you explain why private DefaultInterpolatedStringHandler should not be readonly? If it is as suggests Visual studio then ToString returns an empty string. 🙂
    Thanks !

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

      In the optimized version of the method when the condition is successful, he removed the reference to the default handler as it wasn't needed so had to be able to change that. Though it could have easily be rewritten in such a way that it could be readonly by conditionally setting it in the ctor.

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

    Do the Benchmarks also measure the time GC needs to clean up??? While GC is cleaning up, all TASKs get on HOLD.

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

      It does. It measures it as GC time in all generations

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

    Hi Nick, I admire your work a lot. What about Q&A at 100k subs? :D you could make a post with question and choose most liked. Cheers from Poland!

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

    It seems like string.Concat() could be similarly optimized to prevent the boxing by a bunch of generic overloads. Why hasn't this been done? Has it been proposed and rejected?

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

      You have to balance that memory against the explosion of generic specialization the JIT will need to do to have all the versions of `string.Concat` that you'll end up using. Just given 3 arguments with different types, there are 3^2 = 9 ways of ordering those arguments, and there are way, way more than 3 types in any given .NET program. You'd save memory with boxing, but end up losing it all to the JIT for different method compilations anyway.

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

    Hi Nick, first of all excellent video, congratulations! I’ve an off-topic request: I was recently developing a specific service and I came across that the class in question was getting a lot of dependency injections. After searching a bit I saw that the Facade design pattern could somehow help me, but some people say that it violates some SOLID principles. Could you make a video about this design pattern? Thank you so much in advance.

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

      RawCoding does alot of design pattern videos and has one about Facade
      th-cam.com/video/xzpp5_ak8Hg/w-d-xo.html&ab_channel=RawCoding

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

    I feel like a total noob when I watch your videos. I mean I'm stilla student, but I would like to get to your lvl some day :) Do you have any beginner to intermediate to pro courses for C# and .Net planned?

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

    How can We use faster string interpolations when logging?

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

      You shouldn’t use string interpolation when logging. You should do structured logging instead. It doesn’t allocate any memory with source generators or the delegate approach

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

      @@fabolt But you shouldn't because you are losing the structured logging parameters

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

      @@fabolt In my experience, they are required in most scenarios.

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

    Sucks about the audio line static. Broken cable?

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

      I noticed it in the video I recorded yesterday while I was editing. I will be investigating what causes it today.

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

      Looks like removing the CloudLifter from the setup clears the sound

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

      @@nickchapsas For what it's worth, depending on your setup, you can throw a noise-gate on your recording software to "cheaply" mitigate issues like this.

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

      @@nickchapsas Don't rule out a bad cable yet. Glad you found the link in the chain though!

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

      @@farsidesc4044 Ok so there was actually a noise gate and it was making it less noticable when I was talking. I added the CloudLifter again into the mix and I am getting clean sound so it was probably a loose XLR connection.

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

    YEEEEEEE

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

    I see that guitar in the background, and am afraid you might be as good playing the guitar as you are with coding ;-)

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

    Wow

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

    tl;dr - They made the compilation more complex but fixed the running code

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

    My brain hurts

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

    Hey great video, your English is really good. Just a couple of tips, you always speak fast and not very clearly at the start of your videos and it's hard to know what you're saying because of the Greek accent (but the rest of the video is fine). In this video @10:25 you pronounce "Exception" as "Expression". Your videos are great and this isn't meant as an insult at all, just something to help you improve.

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

      Hey thanks! The fast intro is a bit of a meme at this point which is why I’m not slowing it down. In regards to the expression thing, I tend to read words and numbers wrong. Sometimes then number will be 430 and I will say 43 for no reason and it happens with words as well. I usually catch it in edit but I don’t wanna ADR it so I usually just add a text annotation in the video

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

    Legit

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

    Still annoying that I have to $ before the string to use it. I guess that is for the backward compatibility with the old source code, but when a language gets decades old like Java or C#, I think maybe at some point it needs to give up that compatibility for the greater good. Those who still have old source code could use set some sort of compiler option to compile it in the old way, or use some sort of automated tool to "upgrade" the code to a newer syntax.

  • @LucasRibeiro-lx8ve
    @LucasRibeiro-lx8ve 2 ปีที่แล้ว

    any plans to make a giveway of your courses in a near future? :-)

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

      No plans for a giveaway no

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

    It's a shame that struct cannot be inherited.

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

    i'm lost

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

    Wish that declaration of custom InterpolatedStringHandler would've been inherited from a base class instead of using attribute and compiler magic.

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

      Yeah or an interface, it is a bit tricky as it

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

      @@nickchapsas An interface cannot force a constructor signature. And a base class won't work, since the base class has to be part of the BCL. And this is a compiler (roslyn) trick wich is applied before having access to any of the BCL classes. Same goes for example if you want to use IAsyncDisposable on a target framework which does not have that interface. You can grab it from a nuget package, or define that interface in your own project. Since it's compiler magic, this still works on older frameworks. At least, I 'think' that's the reason :)

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

      @@remcoros We wanted DefaultInterpolatedStringHandler to be a ref struct, which precludes any interface or base type implementation.

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

    C# gets way overcomplicated as time goes on...

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

    Anders Hejlsberg is choking on his coffee. Strongly disagree with this kind o contrivedf compiler level kludge.