Thoughts on C# and .NET
For those of you who have experience developing in C#, what are your thoughts on modern C# and .NET? If you have experience with ASP.NET Core, can you please provide some random thoughts about it? Did you or do you enjoy developing with C# or ASP.NET Core?
81 comments
[ 4.0 ms ] story [ 149 ms ] threadBut legacy projects are still everywhere, and not only are they frustrating because outdated language version, but Microsoft is actively removing downloads for old .NET versions I need to maintain those legacy projects.
- Web framework is not quite on-par with Django/Rails. Particularly with auth/OIDC.
- Job market is very sector dependent. Startups just don't seem to use C# whereas big enterprises do.
- Some design decisions in the early days seem to prevent some features being added, e.g. structural typing or union types (not certain this is the reason).
- Some days, like yesterday, your IDE updates and gets messed up and then it's back to writing full variable names like a medieval monk.
- .NET is not really viable for non-server work. There is embedded/desktop stuff but you're going to have a headache outside of servers.
The good:
- When it's working properly the developer experience is like those dreams where you're flying. Rider or VS + Resharper make typing anything seems an incredibly antiquated way of developing. Intellisense means you barely ever need to type more than 2 characters to express your intent. Unlike my experience in Go or Python I just think about intent/data shapes and the tools fill in the rest. No language I've ever worked in comes close to reducing the ideas -> implementation effort barrier.
- Type system. This is non-negotiable for me, plenty of syntactic sugar to make overhead of typing lower but because it's compulsory, types save so much mental effort and our production systems never wake us up, feeds into the above. You don't just have to reimplement a compiler badly through unit testing saving a lot of time.
- Tooling, full framework used to be hell and very tied to the (paid) tools. Now with Core the tooling is great and Linux support is fantastic.
Overall I don't want to work in any other language if I can stick to C# but the fact startups don't use it mean I might have to enter scripting language hell, again.
As an outsider to this ecosystem, desktop development is one of the things that has me interested in C# at all (built in windows stuff + Avalonia + Xamarin and the like).
Can you elaborate this?
Winforms and WPF are still solid choices if you need a Windows only UI and I think Avalonia is still going and might be good, I haven't really had an opportunity to evaluate it. But I think desktop still lacks a compelling cross-platform solution post-WPF and adopting early solutions from Microsoft will cause you many headaches and much sadness.
.NET MAUI? Who the heck knows, it's still C# only.
[0] Though of course the question then is that if you are building WinUI 3 apps and don't need cross-platform why you don't just use WPF directly, and I don't have a good answer there. I think MAUI might be slightly more appealing if there was a stronger bridge from "start with a WPF app then expand it to MAUI". (You can do it, in some ways it is straightforward, but it's not an official garden path.)
(ETA: Though I get you on the VB.NET as gate idea. It's a big reason I still don't entirely trust Razor much less all the hype around Blazor. Blazor more than anything feels way too much "for people that missed Silverlight, here's a worse ASP.NET Core Silverlight" with shades of ASP Classic runat="server" full circle)
My home automation system runs as a .NET Framework WinForms app written in VB. I'm interested in moving it into two directions: I would rather run it as a service, and I would like to be able to run it on Linux. VB .NET works on .NET Core in Linux environments, without a UI framework like MAUI, this should be trivial to accomplish both... right? RIGHT?
Visual Studio happily provides a .NET Framework template for building a Windows Service (for C# or VB), which my app could work under pretty easily. Or there's a Worker Service template which is cross-platform .NET Core (for C# or F# only... for no technical reason whatsoever, Microsoft just didn't want to bother)
The Windows Service template provides basically the scaffolding entry points for every way you interact with a Windows Service, you can pretty much just paste the code in for what happens when the service starts and stops. This is straightforward and easy and you can tell was designed by the same sort of people who came up with the WinForms editor: It's simple, it's obvious, and anyone can do it. I wrote my first practical Windows service one day, and it was done that day.
There's instructions for turning a Worker Service into a Windows Service here: https://docs.microsoft.com/en-us/dotnet/core/extensions/wind... I think it's safe to say, this is not simple or straightforward in any way (especially since "Rewrite the entire worker class" is a step here...
And that gets you back to... a Windows-only service? What the actual heck?
So here's what I am mind-boggled hasn't happened here: Microsoft should have a cross-platform service template (in all supported languages, please and thank you), and it should give you entry points for starting and stopping the service and such which are all pretty much the same between operating systems, and then it should handle the scaffolding to translate it to the appropriate OS out of the box.
At this point, personally, given the choice, I'd rather just create boring CLI applications that I can stick in cron jobs (or Windows Scheduled Tasks) than ever create another Windows Service if I can avoid it.
Given how dumb it is to create Windows Services and how dumb it is getting to create systemd-style services for Linux I can't possibly imagine how anyone could abstract that well cross-platform. That sounds like an awful minefield to create lowest common denominators that no one likes.
I think we already have such a cross-platform abstraction: it's classic CLI apps and whatever task runners you can find/stomach. .NET Core/.NET 5+ is great at cross-platform CLI apps.
I think the .NET Core templates are really demonstrating a lack of understanding of why Visual Studio has thrived for this long.
Completely wrong. Not only does Auth work particularly well out of the box, but microsoft documentation is top tier with both c# and asp net core.
https://docs.microsoft.com/en-us/aspnet/core/security/authen...
asp net core is the single best framework for backend web at this time, but yes, won't be as fast to ship as django/rails. If you like to maintain code, I'd consider it a worthy tradeoff.
The other thing that works against me in having a Django-like experience with web is I always switch away from EntityFramework as early as possible in favour of handwritten SQl. I think a fair comparison probably puts EF level with or ahead of Django.
But this auth documentation looks interesting and definitely an improvement.
https://docs.microsoft.com/en-us/aspnet/core/security/authen...
https://duendesoftware.com/products/identityserver
They like to hide their dirty laundry behind clever developer advocacy teams and drowning it in Github bureaucracy but here are some examples:
https://github.com/dotnet/AspNetCore.Docs/issues/25832
https://github.com/dotnet/AspNetCore.Docs/issues/7644#issuec...
https://github.com/dotnet/AspNetCore.Docs/issues/24157
https://github.com/dotnet/AspNetCore.Docs/issues/18524
Their PMs are not building an open source product in good faith. As far as they are concerned, ASP.NET Core primarily exists as a funnel to send customers into Azure or buy stuff from Microsoft partner companies. Imagine if Vercel one day removes the standalone server hosting option and requires you to pay for their serverless cloud to use important features. This is what Microsoft is doing here right now with ASP.NET Core. If you lock your stack into their ecosystem, then be prepared to spend money either on redundant cloud subscriptions or developers reinventing the wheel on core features
I somewhat sympathize that Duende's unpaid support costs went up once Microsoft pointed a lot of heat their way by including it in official samples, and they should get paid for support. I also somewhat sympathize that closing their source was seen as the easiest option to redirect the community to paid support plans.
But it's still a jerk move in the Open Source community to have code be open source for more than a decade and then close it simply because it was used in one tutorial/sample too many.
Sure, Microsoft could have offered sponsorships or other help, had Duende asked. Supposedly Duende didn't ask, their first public response was when they immediately went closed sourced because apparently they never really cared about Open Source.
There are people not building an open source product in good faith in this story, but it doesn't seem to be Microsoft (surprisingly).
Microsoft probably should replace IdentityServer with something that actually wants to be good Open Source in the samples again. They are between a rock and a hard place because if they fork the last Apache versions of IdentityServer they look like the bad guy for "stealing" Duende's work at that point, and they can't resurrect their old code because it was bad. They probably have to wait for some third party fed up enough with paying Duende for bad faith Open Source to make their own fork.
> They did that with JSON and created an in-house alternative to Newtonsoft's fast JSON library once it became popular enough. I didn't hear any PMs whining about "competing with the open source community" then.
James Newton-King, the "Newton of Newtonsoft", was one of the developers involved in that project that decided a clean compatibility break with JSON.NET (which has been showing its age, but also has far too many users to easily break API compatibility) was necessary to achieve the performance goals that System.Text.Json was created to meet. That's not so much competition as it is cooperation.
Agreed Intellisense is pretty good. Not excellent - it never suggests using statements as a first option, and in unit tests I have to always type "Asser" to bring up "Assert" (using 2022 expensive version). But it pretty good.
From a tooling perspective, this a positive. From a language perspective, well there are other languages that allow flow-of-thought without needing the tooling to autofill [0]. There are tradeoffs, and practically speaking you'll need to eventually look at someone else's flow of thought and expect them to understand yours.
[0] https://www.wisdomandwonder.com/article/10231/if-you-like-li... "...by and large, I find that the language allows me to express myself, in the language, about the things I’m dealing with. I find that a very precious property of a programming language."
Its refreshing to have types and have to say what the return type is without it being some type of pseudo enforced type as mypy or typescript. But as others have said, c# in the wild is most likely for big enterprise software which is not always the most fun thing to work on.
The stack is ASP.NET Core with .NET 6 on the backend, React on the frontend, Postgres as the database. Not in production yet, but planning to make a lot of use of AWS, particularly Lambda. I'm loving it, feeling very productive and trying to take advantage of many of the new language and framework features.
The biggest downside I've run into is that so much of the documentation and online material is geared towards older versions and older patterns. It makes sense given .NET's long history, but it's definitely been a journey trying to figure out modern best practices without ending up in an overarchitected mess (repository pattern everywhere!). The other thing I would say about C# is that I would never again interview with it, unless it was for a .NET position specifically. All the typing benefits work against it in a timed interview environment. Long time ago I picked Python up for interviews specifically and it was a much better tool for the "job".
Now for some context. I developed in .NET exclusively for ten years, from 1.1 to 3.5. The development environment was great, but over time the Microsoft ecosystem began to feel stifling. Everything had to be done the Microsoft way, if you step off the rails, you'd be in a world of pain. It was a mega monoculture spanning the entire stack, with high tolerance for throwing away previous standards (so much churn with Webforms/MVC, LinqToSQL/various Entity Framework versions, all the WPF/WCF stuff, and I'm sure much more since then). In the mean time the open-source world was moving fast, developing new patterns and technologies, with Microsoft attempting to follow, slowly. I left the ecosystem in 2014 vowing never to return. Yet... the .NET Core cross-platform push intrigued me and the ability to write C# purely for backend APIs that can be deployed outside of Windows felt like a win-win. Time will tell, but so far so good.
I do internal dev tooling in C#. It’s one of the best languages out there for raw “get shit done” prowess. I’ve used many languages throughout the decades, some more elegant than others. Like others, I’m a bit wary of the explosion of syntax shortcuts and alternatives, but whatever, its no big deal. It’s a great all-around, general purpose language. I would love to use F# more but I don’t think some decisions they’ve made would go over well with many people.
I'd love to know more about what you think and are referring to.
Without that stigma it's fine, .NET has a lot of answers to various things even if you have to deal with the Microsoft flavor. Similar to Java which still dominates most of the market in the same space.
Why?
Currently, I don't have a ton of time to maintain the app and I was hoping to migrate it off of aws (since I don't have a ton of aws experience and mostly don't want to mess with it/ manage it) so I was looking to deploy on heroku which doesn't support C# as of now. - https://help.heroku.com/PAT3YEDU/does-heroku-support-net-app...
If you get past my gripe, I think it's much harder for new developer to pick up.
I think Ruby/Rails and Python/Django were created specifically for developer happiness and ease respectively.
I don't think it's going to be easy to manage this asp app (even though it isn't a large code base) Simply due to the fact that there is a lot of stuff I feel like I'll need to catch up on. When I look at other apps written for the web I find them to be "easier", whatever that means.
Pros:
- Excellent documentation and widely used (not just modern btw, MS documentation is world-class and has been for the ~8 years I've been exposed to .NET API documentation)
- Excellent code structure, supports very large/enterprise type code bases
- Mostly sane improvements, with regular rollouts
- Now cross-platform (although ref [0] for what it's like to develop in a non-Windows environment)
- IDE support is 5-star. MS own IDE is at least 4 star, and Rider (JetBrains) seems to be very popular as well. I've used three versions (pre-2019, 2019, and now 2022) at different paid levels, no big gripes. You get great debugging, profiling, REPL, etc.
- Mostly opinion/experience: Allows for a range of styles, while IMHO balancing correctly with consistency that is easy to pick up and collaborate with. It is possible to write confusing code, but not as much as other languages (ref [1]).
Cons:
- It is cross-platform according to the docs, but in reality it comes from and is relied on mostly in a Windows world.
- Testability - if you like unit testing, you will need to make everything testable also exposable - if not publicly, at least within the same assembly.
> If you have experience with ASP.NET Core...
Yes. It's pretty good. Apart from a question specific to the language or framework, you will need to quickly become familiar with how stuff works behind the scenes. It might also be beneficial to look into how deployment works, depending on your target (IIS, Azure, AWS, etc).
> Did you enjoy developing...
Yes, for larger projects that need collaboration. Otherwise I use Ruby.
[0]: https://news.ycombinator.com/item?id=31520399 [1]: https://www.ioccc.org/
* edited for formatting
I'm not sure I've ever used the "internal" keyword in 12+ years of C#. Assemblies are about deployment; public/private is about the contract your code is agreeing to. They have nothing to do with each other, so internal is an inappropriate conflation of concepts, by definition.
Downvoter, the problem with your downvote is that I am correct. DLL dependency/deployment is a completely separate concern from code contracts and visibility; therefore "internal" is always a mistake and should never have been added to the language. If you use "internal", we've identified that you have gaps in your understanding of software development that you have the opportunity to fill. But instead, go ahead and just downvote me again without comment. That's a lot easier than improving.
The way other projects can access these services is by using the project's helper to register them all in the DI container by their interface. That way I can be sure no one is directly using the classes and make breaking changes to the constructors (like swapping loggers or api clients), but still access them from tests.
If they overwrite each other, you might be able to get away with calling the god-registration-functions in the correct order (which you can determine only by reading the source code of the two functions, which are probably in different solutions), but if you really have a well mixed set of needs from A and B, this is probably not possible.
So you say: "okay, well, in this case maybe those concrete services should be public instead of internal. Obviously in this case we'd go back and do that." So your logic is: use "internal", except when it turns out we shouldn't have used it, then don't. So what purpose was it serving to begin with? None. The last lesson is that if you find yourself saying "in this case", you're actually talking about every case. That is to say: "special cases" are a symptom of a weak mental model. Good models don't have special cases.
So indeed we've identified several ways to improve, all stemming from the fact that you are using the "internal" keyword!
Not my experience at all, everything I do at work is c# on containers running Linux.
One of us is doing testing very wrong then. Maybe I don't like "unit testing", if that means reaching into the internals of every class. Just test that your code is following the contract it says it's following.
The idea that you need to test private methods by running them out of context sounds to me like someone saying "A downside of this language is that you can't jump into the middle of a function to test individual lines of code. You can only run functions from the beginning." Yikes!
Usually testing output from a contract implementation works just fine. But sometimes my implementation contains bits abstracting parts of the whole. Those bits needs to be tested too, even though from an outside perspective there's no need to expose each bit. The consumer is only interested in the whole result.
A consumer of the contract may want to pass in a Dog object, and get a result that tells if it (the dog not the consumer) has fleas. My implementation will result in true or false, but I'd like to abstract and separately test the parts that checks if the dog itches, if it has tiny animals flying in a cloud around its head, etc.
I like good sane code coverage, but I also want it to be clear what is expected to be publicly consumed to drive the business logic, and what's just me making things tidy behind the scenes.
How did I end up in another conversation about unit testing?
Otherwise that code is unreachable and should be deleted.
- Documentation: is ALL over the place. I do not find it excellent. There is LOTS of documentation but due to naming (.NET framework != .NET Core != .NET Standard != .NET [current]) you can find solutions that just don't work in the version you're in. Blogs are often the best source of details, but you have to have great search-foo to find the right one, and like stack overflow these won't age well (especially with the new rapid release cycle). There is documentation, and lots of it. *Warning*: On the MS official docs you can set the .NET version (with a drop down in the top left).. however if you try and visit something outside of that version, it will take you there and silently switch you to the last version where it was valid.
- Improvements: are great, they see what's happening in other languages and incorporate it. .NET might not be the first to have (although sometimes it is: `async`) but eventually gets the best solution to a problem (`Span` is rather like `slice` in golang).
- Cross platform: is very strong. Doing it the cross platform way is completely subject to the documentation trap above. A lot of the docs out there are for .NET Framework (the OG, which is not cross-platform) so you start off down the wrong path not realizing there's a cross platform way. This compounds pretty quickly.. if you're building cross platform, setup automated cross platform CI early.
- Testability: It seems you have not discovered `InternalsVisibleTo`[0], available as both a class-decorator or a project assembly attribute. It's been around since .NET Framework 2.0 (2005). Very much like the C++ `friend` declaration. You can allow a test assembly (only) to see private/protected/internal pieces of your assembly, if you desire.
- .NET (formerly .NET Core): Is great. Faster, leaner, and their future. Subject to the documentation trap above. Because of their rapid releases (and good comparability guarantees not forcing upgrades), it can be really hard to find good examples/docs of the newer releases.
[0]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.c...
There are a ridiculous amounts of ways to declare a variable.
And that doesn't even count the initializers {}, records, dynamic, etc... All this makes it difficult for a new develop to jump into it.The last one is a very recently added shorthand which, honestly, I think was just implemented because an intern needed a feature on master to get hired or something like that... I don't get it either.
1: https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...
> The language does appear to show its age though.
Come to Java land. It takes decades to add a single feature. Grass is always greener.
1) As time goes on, C# is increasingly just F# with different syntax. LINQ, closures, records/immutable structures, and so on - you can write code in C# that is more functional than it is object oriented these days. This is mostly a good thing; it also means that (to my eyes) the language has become much more elegant over time.
2) The level of cross-platform compatibility you can get if you're using .NET Core or .NET 5/6 is pretty fantastic. Performance has also improved dramatically. C# is in no way limited to Windows as an environment anymore - unless you have a dependency on .NET Framework.
3) Everybody has dependencies on .NET Framework. Those who don't have dependencies on unmanaged Windows DLLs.
4) Great debugging/developer tools, as others have mentioned. VS and Rider are both top-of-the-line IDEs.
5) C# is not and will never be cool, sexy, or the thing of the moment. It is a language for getting things done in an easy-to-comprehend way and that's just about all it is. I like it very much.
There's no issues using a library written in one .NET language from another .NET language though, so if you can break the project up a bit more, you can work in multiple .NET languages.
I hope the AOT story continues to evolve and come down in size so I can start writing small utilities in it.
However in term of recent evolution, I feel that under Anders Helsberg there was a focus on simplicity. Then Anders moved on, and anarchy followed, with multiple frameworks, multiple attempts to combine them into one framework, and ultimately the greatest of all sins for a language: breaking backward compatibility (.net 4.8 vs 6). And it feels everything is getting complicated, command line first, async everywhere which makes everything multithreaded, prone to deadlocks and hard to debug.
The original c# had a great set of core libraries, however it has now fossilised. I think the owners of C# feel it is not their job to "update the batteries". So for instance their drawing library still doesn't support HEIC and might never do, they only added a json serialiser recently (yaml probably never). Instead you need to rely on a myriad of third party libraries with version conflicts, dozens of assemblies, and god knows if they will be available or maintained 10 years from now.
So while I am heavily invested in C# myself, probably too much to switch now, if I had to start from scratch now, I don't know that C# would be my first choice. But the need to rewrite everything for .net 6 might give me the opportunity to do that however I really don't have the time for that now.
I do most of my C# development on Linux. Not sure why you need to tolerate Windows to enjoy C#.
And Visual Studio. To me the IDE matters as much as the syntax of the language. And when I was a beginner having an IDE that can interact with my code as I type it is a massive help to progressing.
All in all, I’d say the port for our large suite of server apps, with lots of different CPU/memory bound and network I/O bound apps, it was quite straightforward and easy.
What killed it in the end for us, was that our testing showed our CPU/memory bound apps ran 0.9x as fast on Linux .NET Core 3.0 vs. Windows .NET Framework 4.6/4.8 OR .NET Core 3.0, using near-identical hardware. The Linux port just wasn’t there yet, so we decided not to go through with any port to .NET Core for any part of our system, since Linux would have been the main benefit (we were using fancy network cards and stacks, and the Linux support for those was far more advanced and reliable compared to Windows, where multicast groups would spontaneously fail to be joined, etc.).
Another elephant in the room, is that GUI support on .NET Core was limited at the time, so we may not have been able to do a Big Bang for that reason also. We had a few WPF apps, and some Forms stuff, but I have no clue about what .NET Core support was/is for that stuff, as I rarely worked on GUI things (I would create a GUI as a necessary part of an experiment and hand it off to more experience people, or modify/simplify GUI logic as part of my evolution of our server stack, but that’s all).
So obviously YMMV and it seemingly does vary, but my experience on server apps that weren’t using lots of Windows/MS specific technologies (I’m not a fan of them generally), our porting was really quite easy. Still a failure though :-)
On the recreating project files, I don't think you can copy-paste winform code like that, you need to recreate it using the UI, which is a pain. Also they had this weird concept that an assembly had to be set to be a "winform" or "wpf" assembly, you couldn't simply reference system.windows.forms, which basically prevented you from creating a helper winform assembly, and you certainly couldn't create an assembly that referenced both winforms and wpf DLLs. They perhaps also fixed that since.
In any case, it's not a complete rewrite to migrate to .net 6, but it is far far from a simple lift and shift.
GUI stuff is also what happened in .NET 5+. WinForms and WPF were both added to .NET 5. There's some porting that needs to happen and not all old WinForms/WPF code will be happy on .NET 5+. The biggest remaining "missing piece" from a GUI perspective is that a lot of old WinForms/WPF code used WCF for service code. I think porting WCF to use simpler REST services is easy enough and there's lots of people doing that with gRPC services in .NET 5+ too. There's also the Open Source CoreWCF project that is trying to hit compatibility with the most used bindings in WCF on top of .NET 5+.
I’ve been saying “we”, but I left that job a couple years ago so I won’t be trying any new .NET versions myself :-)
However, “too invested to switch now” reminds me of .NET/C# developers that don’t embrace change and/or don’t swim in other waters.
Some folks with a traditional Microsoft/Windows/.NET Framework mindset have real trouble with these things:
>“Windows and Visual Studio”
Rider, Linux, Docker, bash terminals, and MacOS are all things that can improve your ability to solve problems with .NET. I’ve met dozens of people that refused to even try a different OS/IDE and fail to gain the benefits of those tools and the broadening effect they have on your perspective.
>”too many frameworks”
This complaint sometimes stems from an unwillingness to learn web/mobile frontend technologies. On the server-side, ASP.NET continues to simplify— you can write an API now in one file with a handful of lines of code. [1]
>“limited core libraries”
The first party support in .NET is already pretty comprehensive. Some folks have an aversion to using open source packages, but this is exactly how you get things like YAML parsing in most other languages. Microsoft’s move to open source has been awesome. You can literally interact & contribute with the team’s that make the framework.
>”command line first”
This sounds like a feature to me. This allows for automation and is easier to document without a series of screenshots. Having a common CLI allows a team to mix their preferences of IDEs/tools.
>”async everywhere which makes everything multithreaded, prone to deadlocks and hard to debug”
I disagree. async/await makes it easier to write readable code without deadlocks or many of the other pitfalls of multithreaded programming. It is not inherently multithreaded either [2].
Since it’s ‘everywhere’ and thus fundamental to writing C#, it’s my first interview screening question. A large number of candidates, with a lengthy .NET background fail to articulate any issues with calling “.Result” or “async void FunctionHere()”. IMO, you have to deliberately avoid understanding such a ubiquitous language feature.
[1] https://docs.microsoft.com/en-us/aspnet/core/fundamentals/mi... [2] https://blog.stephencleary.com/2013/11/there-is-no-thread.ht...
Or I have other things to do and I don't want to have to relearn and rebuild everything for no obvious benefit. I have no fascination for the tool, I am keen on what I can do with the tool. Having to rewrite something I already did because someone decided to change the internal architecture of a core part of the framework is a waste of my time. The .net team used to understand that.
> This complaint sometimes stems from an unwillingness to learn web/mobile frontend technologies. On the server-side, ASP.NET continues to simplify— you can write an API now in one file with a handful of lines of code.
that may be but compare the amount of time it takes to drag and drop a button on a winform, double click on it and write your code vs doing the same thing web based. I also do websites, but the time invested to do a simple UI is an order of magnitude what it takes with a desktop app, so I need to have a really good reason to go web based for a home or internal project (and now I need to deal with a server with certificates, etc). And there are many applications where it is simply not possible. Interacting with files, or visualising non h264/aac videos, selenium, etc.
> This sounds like a feature to me
I am not saying it is not intended, I am saying it is more complicated.
> It is not inherently multithreaded either
Yes it is. You need to constantly think whether you are going to come back on the same thread or not. Something that works fine on a console application or within an exceldna formula will deadlock on a asp.net or wpf application. And it breaks the call stack when you get an exception, making it harder to debug. I think I understand this feature reasonably well, thank you.
And not just multithreaded, asynchronous also. That means if a user clicks a button and that button has async code, the user can do more interactions with the UI while the original method is running. Now you need to handle many more UI states than you had without async.
The beauty of types in this case is that the JSON structure has a natural way to be expressed in C#… we just need to utilize it
Or a JsonNode if you don’t know the structure
The documentation still includes pages on dynamic, even though dynamic has become a mostly forgotten feature and there are still developers that would never use dynamic. For example: https://www.newtonsoft.com/json/help/html/QueryJsonDynamic.h...
I appreciate that dynamic exists in C#. I've done some wild things with dynamic over the years. It sometimes makes me sad how under-appreciated a tool it can be.
ETA: Obviously dynamic is not type-safe, it's a great escape hatch from type safety for small cases where "just do what I want" is nicer/more natural than type safety. As the sibling comment points out, if you still prefer type safety there are type deserializers that can be easier to use. These days with records in C# 9+ writing quick types to deserialize to is even relatively painless.
https://www.howtosolutions.net/2020/07/visual-studio-creatin...
There are exceptions like Game Development of course.
Nothing beats this language for getting REAL work done in my books.
Tooling - Visual Studio absolutely unmatched. Core Lib/Type System - one of the best. ASP.NET Core - great rewrite of the old ASP.NET. Very fast. Runs everywhere.
C# as a language has evolved very, very nicely and I try to use the new feature whenever it makes sense.
The bloat is a bit much, but once you get used to it, its a damn good eco-system.
Bloat is also being rapidly shed with many improvements. .NET 7 (the upcoming version) is going to be even better.
The programming and architecture practices recommended by MS are great for most apps.
Pros:
- Superb IDE. Nowadays even without Resharper, which was a must have in my early C# days.
- Massive standard library and extensive documentation makes for a very productive development experience (especially backends).
- dotnet core was a huge leap forward in terms of dev tooling (sane cli, 3rd party integration) and framework flexibility (configurability in general, config by code instead of XML)
- Microsoft keeps adding language features copied from functional programming languages.
Cons:
- Enterprise culture is very pattern-centric and produces much boiler plate code. That's the main reason I want to move away from dotnet.
- Desktop apps are not cross-platform and I don't trust their newer stuff to deliver on that promise. The older WPF is outdated (e.g. no inbuilt support for "newer" features like async/await) because of their focus on Xamarin and MAUI or whatever new fad they come up with.
- Microsoft seems to swallow open source libs by integrating them or copies of them (e.g. Newtonsoft.Json) into the standard lib. I'm not sure if this is a good thing. I know I'm contradicting the "massive standard lib" pro from above. But here I'm thinking long-term.
- New language features are sometimes done half-assed for backwards compatibility. E.g. nullable reference types that are just syntax sugar instead of a proper maybe monad with language integration.
The .NET approach of ensuring you can do nearly everything an app might need basic functionality-wise in the standard library probably sets .NET as one of the most secure platforms to develop with.
It's the anti-NPM, and NPM is terrible for security.
1. Fast compile times for most of development. I'm fine with waiting a while to do a special highly optimized deployment, but getting 95-100% of optimal performance with 0-3 second build times is really nice.
2. Controllable memory access through value types. Nothing getting in the way of C-like contiguous buffers and managing cache line or load alignment.
3. GC that gets out of the way. C# has a GC, but in most of my applications the GC never has to run because I rarely allocate GC-managed instances. It's definitely a nonidiomatic use of C#, but the fact that it's pretty still pretty easy to do is nice. And when I don't have to care about the GC's overhead, the presence of the GC just makes everything easier developmentally.
4. Ability to actually make use of the hardware. The compiler's improved massively in the last several years, and the way vectorization is exposed actually feels a lot nicer than my experiences in C++-land.
And less relevant to my own needs, but still interesting, nowadays you can directly link a C# library into a C/C++/Rust application just like any C library. Among other things.
Almost a decade ago, I was considering exiting the ecosystem in favor of C++/D/not-yet-even-1.0 Rust/etc, but the open source push and a sudden focus on performance basically made the jump unnecessary. C# occupies a really nice sweet spot.
Value types are indeed very cool, and I really hope they will get implemented sooner on the Java side as well. Just as a note, Java recently got a SIMD API as well.
I wrote a bit of stuff a few years ago: https://www.bepuentertainment.com/blog/2018/8/30/modern-spee...
Some of the implementation details (like the operator codegen) are surprisingly outdated now given the speed at which the runtime has moved (and the library is now ~4x faster or something silly like that), but the fundamentals are still there.
Since I wrote that, codegen has improved a lot, the hardware intrinsic vector APIs have offered a way to optimize critical codepaths further, additional cross platform vectorization helpers have made it even easier, NativeAOT is getting close, and all sorts of other stuff. The C# discord #allow-unsafe-blocks channel contains a variety of denizens who might be able to offer more resources.