Live data from Hacker News

Why Custom Attributes in .NET Give Me Nightmares

blog.washi.dev

11–20 of 30 posts

Re: Why Custom Attributes in .NET Give Me Nightmares

#12
post #8
post #5

I try to avoid using custom attributes to configure things like business logic because they struggle to account for interactions between members. Attributes have no affordance for lambdas, delegates, method references, etc. You would need a separate piece of logic that interprets the primitive attribute data in order to provide any emergent properties between members. A better approach is often to expose some abstrac…

The only case I've used them was to mark classes that I need to find via reflection and do something with them. For example a migration system where you want to load all migrations that are defined and check if you need to run them. Of course you don't really need an attribute for that, but I find it helpful to leaven a marker on the class that there's something else going on there.

To solve this problem I have seen the following pattern:

1. Create an abstract base class named MigrationBaseClass 2. Have all migrations classes inherit from MigrationBaseClass 3. Use .Net Reflection to get all types that inherit from MigrationBaseClass 4. Do something with these types.

Re: Why Custom Attributes in .NET Give Me Nightmares

#13
post #3
post #2

.. if you're trying to parse the assemblies by hand for some reason. If you're just trying to handle them with reflection none of this is an issue.

> If you're just trying to handle them with reflection none of this is an issue But maybe indicates on how expensive that reflection call can be? Reading multiple .dlls ?

Be careful with this sort of logic ("reflection=expensive").

Everything should obviously be measured.

I've worked with large .NET code bases that used attributes for things like plugins and it was completely negligible for overall performance in the grand scheme of things.

Re: Why Custom Attributes in .NET Give Me Nightmares

#14
post #12
post #8

Earlier quoted context omitted.

The only case I've used them was to mark classes that I need to find via reflection and do something with them. For example a migration system where you want to load all migrations that are defined and check if you need to run them. Of course you don't really need an attribute for that, but I find it helpful to leaven a marker on the class that there's something else going on there.

To solve this problem I have seen the following pattern: 1. Create an abstract base class named MigrationBaseClass 2. Have all migrations classes inherit from MigrationBaseClass 3. Use .Net Reflection to get all types that inherit from MigrationBaseClass 4. Do something with these types.

Doesn't even need to be an abstract base class. It's just as easy to use reflection to find all implementations in an assembly of an IMigration interface.

(ETA: Though my favorite pattern here became using DI for this instead of reflection. For every IMigration have a `services.AddTransient()` somewhere and then your service to run all migrations can just request from DI `IEnumerable`. I can then put the Reflection into a unit test to make sure everything that implements IMigration is registered in the DI container. But using DI in the main assembly to register all the migrations rather than Reflection leaves more room to try to AOT compile the assembly in production builds.)

Re: Why Custom Attributes in .NET Give Me Nightmares

#15
post #12
post #8

Earlier quoted context omitted.

The only case I've used them was to mark classes that I need to find via reflection and do something with them. For example a migration system where you want to load all migrations that are defined and check if you need to run them. Of course you don't really need an attribute for that, but I find it helpful to leaven a marker on the class that there's something else going on there.

To solve this problem I have seen the following pattern: 1. Create an abstract base class named MigrationBaseClass 2. Have all migrations classes inherit from MigrationBaseClass 3. Use .Net Reflection to get all types that inherit from MigrationBaseClass 4. Do something with these types.

yeah, there's plenty of ways to do that. I like having the attribute there so that there is a strong hint that some magic is happening somewhere with that class.

Re: Why Custom Attributes in .NET Give Me Nightmares

#16
post #9

FWIW, Custom Attributes in .Net are kind of a pain in geneal, powerful but painfull... Probably why JS still doesnt really have them in practice.

The language doesn't, but I'd say the language integration isn't the tricky part of this kind of cross-cutting-concern code. In JS you could imagine a function that decorates classes in some way, or React HOCs, etc. (We don't do HOCs anymore because we have a new kind of kludge, but we used to.)

The tricky part is as someone mentioned elsewhere in the thread: the attribute doesn't account for interactions well. You might want it to alter its behavior in different situations but the whole point is that it's cross-cutting and treats everything the same. (And I would say, even though I just called React hooks a kludge, that they are less cumbersome in this respect than HOCs were.)

Re: Why Custom Attributes in .NET Give Me Nightmares

#17
post #12
post #8

Earlier quoted context omitted.

The only case I've used them was to mark classes that I need to find via reflection and do something with them. For example a migration system where you want to load all migrations that are defined and check if you need to run them. Of course you don't really need an attribute for that, but I find it helpful to leaven a marker on the class that there's something else going on there.

To solve this problem I have seen the following pattern: 1. Create an abstract base class named MigrationBaseClass 2. Have all migrations classes inherit from MigrationBaseClass 3. Use .Net Reflection to get all types that inherit from MigrationBaseClass 4. Do something with these types.

Assuming you have all the code in your solution, you could do this with a source generator instead and have no need of reflection and are AOT compatible

Re: Why Custom Attributes in .NET Give Me Nightmares

#18
post #4
post #3

Earlier quoted context omitted.

> If you're just trying to handle them with reflection none of this is an issue But maybe indicates on how expensive that reflection call can be? Reading multiple .dlls ?

I would expect DLL parsing to be a one-off cost at assembly load time. Certainly that handles all the stuff detailed under "Assembly resolution". Assembly resolution is also recursive, so I would expect that to simplify "type tree traversal" by pre-stuffing all the types into a Dictionary. That also necessarily has the parser for all the "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c…

Wait, I thought one project = one assembly, so you would never have "types in assemblies in the same project which the current assembly depends on".

Should that be same solution instead of same project?

Re: Why Custom Attributes in .NET Give Me Nightmares

#19
> My guess is that Microsoft just does not think it is worth creating an update (especially since attributes usually do not affect runtime behavior).

I wonder if this is why dotnet's startup time is so long? Might be worth revising just to get assembly resolution time down.

Post reply on HN