Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Attributes do nothing at all on their own. It's someone else's code that does magic by reflecting on your types and looking for those attributes. That may seem like a trivial distinction, but there's a big difference between "the language is doing magic" and "some poorly documented library I'm using is doing magic". I rarely use and generally dislike attributes. I sometimes wonder if C# would be better off without them, but there are some legitimate usages like interop with unmanaged code that would be really awkward any other way. They are OK if you think of them as a weakly enforced part of the type system, and relegate their use to when a C# code object is representing something external like an API endpoint or an unmanaged call. Even this is often over-done.

Yes, the ASP.NET pipeline is a bit of a mess. My strategy is to plug in a couple adapters that allow me to otherwise avoid it. I rolled my own DI framework, for instance.

Source generators are present in all languages and terrible in all languages, so that certainly is not a criticism of C#. It would be a valid criticism if a language required you to use source generators to work efficiently (e.g. limited languages like VB6/VBA). But I haven't used source generators in C# in at least 10 years, and I honestly don't know why anyone would at this point.

Maybe it sounds like I'm dodging by saying C# is great even though the big official frameworks Microsoft pushes (not to mention many of their tutorials) are kinda bad. I'd be more amenable to that argument if it took more than an afternoon to plug in the few adapters you need to escape their bonds and just do it all your own way with the full joy of pure, clean C#. You can write bad code in any language.

That's not to say there's nothing wrong with C#. There are some features I'd still like to see added (e.g. co-/contra-variance on classes & structs), some that will never be added but I miss sometimes (e.g. higher-kinded types), and some that are wonderful but lagging behind (e.g. Expressions supporting newer language features).





    > But I haven't used source generators in C# in at least 10 years, and I honestly don't know why anyone would at this point.
A challenge with .NET web APIs is that it's not possible to detect when interacting with a payload deserialized from JSON whether it's `null` because it was set to `null` or `null` because it was not supplied.

A common way to work around this is to provide a `IsSet` boolean:

    private bool _isNameSet;

    public string? Name { get; set { ...; isNameSet = true; } }
Now you can check if the value is set.

However, you can see how tedious this can get without a source Generator. With a source generator, we simply take nullable partial properties and generate the stub automatically.

    public partial string? Name { get; set; }
Now a single marker attribute will generate as many `Is*Set` properties as needed.

Of course, the other use case is for AOT to avoid reflection by generating the source at runtime.


That is tedious with or without a source generator, mainly because there's a much better way to do it:

    public Optional<string> Name;
With Optional being something like:

    class Optional<T> {
      public T? Value;
      public bool IsSet;
    }
I'm actually partial to using IEnumerable for this, and I'd reverse the boolean:

    class Optional<T> {
      public IEnumerable<T> ValueOrEmpty;
      public bool IsExplicitNull;
    }
With this approach (either one) you can easily define Map (or "Select", if you choose LINQ verbiage) on Optional and go delete 80% of your "if" statements that are checking that boolean.

Why mess with source generators? They're just making it slightly easier to do this in a way that is really painful.

I'd strongly recommend that if you find yourself wanting Null to represent two different ideas, then you actually just want those two different ideas represented explicitly, e.g. with an Enum. Which you can still do with a basic wrapper like this. The user didn't say "Null", they said "Unknown" or "Not Applicable" or something. Record that.

    public OneOf<string, NotApplicable> Name
A good OneOf implementation is here (I have nothing to do with this library, I just like it):

https://github.com/mcintyre321/OneOf

I wrote a JsonConverter for OneOf and just pass those over the wire.


> But I haven't used source generators in C# in at least 10 years

Source generators didn't exist in C# 10 years ago. You probably had something else in mind?


Huh? 10 years ago was 2015. Entity Framework had been around for nearly 7 years by then, and as far back as I remember using it, it used source generators to subclass your domain models. Even with "Code First", it generated subclasses for automatic property tracking. The generated files had a whole other extension, like .g.cs or something (it's been a while), and Visual Studio regenerated them on build. I eventually figured out how to use it effectively without any of the silly code generation magic, but it took effort to get it to not generate code.

ASP.NET MVC came with T4 templates for scaffolding out the controllers and views, which I also came to view as an anti-pattern. This stuff was in the official Microsoft tutorials. I'm really not sure why you think these weren't around?




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: