Hello World in .NET written using IL code
HTML-код
- Опубликовано: 16 сен 2024
- Subscribe: bit.ly/ChapsasSub
Become a Patreon and get source code access: / nickchapsas
Hello everybody I'm Nick and in this video I am going to have a little fun by writting a .NET application that prints Hello World! by emiting IL code. IL or Intermediate Language is the language that C#, VB.NET and F# will all compile into and it's what the CLR or Common Language Runtime, will ultimately execute. C# provides a way to emit that IL code and this can be used in multiple things from building dynamic proxies to speeding up reflection.
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
Metaprogramming never fails to surprise me with each new way of writing code to avoid having to write code.
yes, more IL tutorial please!
Your HelloWorldWithIL code actually could be translated to IL code using C# as well, creating the HelloWorld inception nightmare
I remember doing this for a university compiler project back in the .NET 2.0 days. But then System.Linq.Expressions in .NET 3.5 made it all obsolete.
Nick's a smart guy.
This is so cool! IL this kind of stuff.
The average developer does not need this. But they should at least know about it.
A typical use case for this is when you build have to generate IL code in memory, like when building a compiler, or for some optimized task.
And a lot of compile-time tooling is based around Reflection.Emit or Cecil. That can now be replaced by Roslyn and source generators.
There is even a third-party package called Cecil that is used for inspecting and building assemblies - without dependency on Reflection.Emit.
Nowadays, people can use Roslyn and source generators to generate high-level C# code at compile-time instead. It is easier to debug, and suits better for most cases.
This is partially true. Yes 99% of .NET developers don't need to know how to do this. That being said I disagree with the source generator statement. I think they both have their place for various reasons. Firstly, Source Generators are only supported on specific dotnet version and specific C# versions, while IL emittion works across the board. It is also fundamentally different since one will emit IL code directly while source generation is subject to lowering and then IL emition (which is not the same). You don't get to control IL with SG but you do with IL emit (and some times you need to). Source Generators have a long way until their developer experience becomes acceptable (it is currently horrible to work with). You won't see Moq migrating to source generators anytime soon.
As a side note, my content is not necessarily there to teach something (that's why I explicitly make it shorter than other people in the same area), but it rather acts as a catalyst to get someone started on a topic. This video is no different.
@@nickchapsas I agree. I know that they are not the same, and of course there are limitations.
What I meant to say is that tools have been using Reflection.Emit for emitting compile-time structure or IDE experiences, in cases where you, today, could use source generators.
You need know on what level you need to generate code.
Anyway, I’m a compiler nerd so I have experimented a lot with IL and metadata generation. It is fun generating IL and to see it run 🙂
Keep up the good work with your channel!
Why would you want to do this though? What do you get out of it to create assemblies during run time?
I guess you could have a config file, and then create different assemblies based on the config... But it seems a bit gimmicky
Unit testing mocking frameworks are built this way. You can also significantly speed up reflection to be as fast as actual compiled code. Is more use-case specific for sure, but certainly something you should be at least aware of
is there any reason to do this? like can you actually out-code the compiler?
Technically it depends but I wouldn't try to out-code the compiler because the compiler evolves and might out-code you by upgrading. This is very valuable if for example reflection absolutely is the only way to do something but you want it to be as fast as possible. IL Generation for proxy classes and other things is also a very valid usecase but it might eventually become less relevant as source generators evolve.
You can do things that C# doesn't allow. For example, you can make a int ReinterpretFloatAsInt(float x) value by doing
ldarg.0
ret
This will load the first argument onto the evaluation stack, then return the value. Since the argument is float but the method returns int, this will effectively reinterpret it as an int. IE. you'll get the raw integer value of the float, equivalent to return BitConverter.ToInt32(BitConverter.GetBytes(x)); but significantly more performant.
Just an example.
@@MulleDK19 just use Bitcast if I'm not wrong.
Compilers that run on the crl use it to generate IL code
@@carpal4489 They've added BitConverter.SingleToInt32Bits() in .NET 5. But that's not a language feature. This was just an example of what IL allows.
Does anyone have any idea why Console.Readline can't be called from il?
I tried it with every kind of method ( methods with return types, methods with parameters,methods without any of these) - all of them work.
But if you try to use any of the read methods from the console ,the il fails , givinh you a System.Reflection.TargetInvocationException with an InnerException of InvalidProgramException.
If anyone has a solution i would love to hear it.
Are you using the value? You can't return a value from a void method.
is london always cold? just asking because i think i never saw you without a coat \o/
I'm not sure when we really need to write il code directly
You don't until you have a usecase for it. Then you do.
There aren't many use cases, but one example might be when you need to generate optimized code based on user configuration i.e. you're building a DSL.
@@sheglova I can give you a real world example.
I had to add an x509 certificate to every assembly built for production.
I also had to write an x509 cert validator for these assemblies. the method had been added to the LoadAssembly event handler so every managed dll which was loaded by a given assembly was checked if they contained the required certificate.
And I had to write unit tests for that event handler logic to verify that the cert validation is really doing what it should do.
So how you do it from a unit test? Exactly, you create an assembly (with a "helloworld"-like method in it), load the assembly from a memory stream with Assembly.Load and trigger the validation logic for positive and negative tests. Of course for positive tests you also have to add a valid certificate to your dynamically created and loaded assembly. :D
Now you just showing off 🤨
Is that Rider?
Yep
👍🏽
OMG
Hi nick, what method would you recommend using to store passwords and keys used in source code running in .net core, thanks
Don't store passwords, if possible use hash+randomized salt will provide decent security.
Check out IDataProtector it's in Microsoft.AspNetCore.DataProtection
@@sps014 I may have not explained myself well, I was talking about api keys and db passwords needed to run the app services, not user passwords.
@@pabloturnesg my bad i assumed something else ...
Use a secure key store solution like Azure KeyValut or AWS KMS. I have a video on the subject showing you how to do it.
This is useless. You can't claim to teach IL Emit without any mention of the push/pop sequence of the evaluation stack.
Never claimed to teach IL at any point in the video or the title.