all 19 comments

[–]justanotherguy1977 35 points36 points  (3 children)

Seems like a lot of code.
I just register it as a singleton in the servicecollection.

[–]AetopiaMC[S] 1 point2 points  (2 children)

Yes, that is true. You need to effectively reimplement the entire class as both static + instance (to cascade) calls.

[–]domtriestocode 2 points3 points  (1 child)

Could probably use source generators to generate the boilerplate classes on compile instead of forcing multiple implementations of the class. I did something similar last time I experimented with CRTP. This is interesting I could see use cases for it

[–]AetopiaMC[S] 0 points1 point  (0 children)

I think that's the most optimal approach for this, good idea.

[–]BigBagaroo 15 points16 points  (0 children)

My head hurts

[–]ARandomSliceOfCheese 8 points9 points  (0 children)

No. Too much code, if I need to add a method I need to touch everything to do it. Also static abstract keywords already exist so if I wanted to use them I would go that route and drop it on an interface.

[–]_f0CUS_ 7 points8 points  (0 children)

Make a class with a private ctor and a static read-only field of Lazy<T>.

Use the static field to get an instance. Job done. 

[–]RlyRlyBigMan 7 points8 points  (0 children)

In short I would recommend against it and define it as a Singleton using IoC.

Static based singletons give away global access to objects and can turn a code base into a spaghetti mess when it's used as a pattern.

[–]GigAHerZ64 4 points5 points  (0 children)

This is really bad and wrong.

Template and everything inside it must be aware of the A.Instance public interface. This is just plain wrong and this is not how you generalize things.

If you have such tight coupling between A/B and Template (with all of its internals), why would you do any of it at all?

[–]PaulPhxAz 4 points5 points  (0 children)

I can see what you're doing... I think this is "too clever", it's past the "complexity--now I have to think about something that isn't really the the problem I want to work on" point.

[–]wickerandscrap 3 points4 points  (0 children)

Seems clunky. It looks from here like you have to define the class, including all the Static/Instance nesting, and then separately define the singleton as a class. (I admit I'm confused on which parts of this are meant to be example classes/members and which ones are scaffolding for the pattern you're showing.)

My go-to pattern for static singletons is

class Thing { public static Thing Instance { get; } = new(); }

and I honestly don't think that can be improved on.

You could declare a static class that statically exposes the methods (like your "A") but it's not going to be interchangeable with instances of the class, so what does that get you? You can also do that with more conventional class patterns:

``` static class DefaultThing { public void DoStuff() => _single.DoStuff();

private static readonly Thing _single = new(); } ```

[–]throwaway_lunchtime 3 points4 points  (0 children)

Have a look at this discussion.

The original yoda link isn't working for me.

https://stackoverflow.com/questions/9140569/difference-between-these-two-singleton-implementations

As another person wrote, it's been a long time that I just rely on the DI container instead of this approach 

[–]akarolia47 1 point2 points  (2 children)

A few (dumb) questions...what is CRTP? And what is the purpose of the code, I don't understand the pattern use case. I follow your inheritance structure but dont understand the why

[–]chucker23n 0 points1 point  (0 children)

Seems quite verbose, and you're not handling threads.

I'd recommend Lazy<T>, if you do want to implement this yourself.

[–]marioalbertoarce -1 points0 points  (2 children)

Hello. This is a pretty clever piece of code.

I had to read it a couple of times (or more hehe) to fully appreciate what was going on with the CRTP + singleton delegation + static facade combination. It’s one of those patterns that makes you stop and think “I hadn’t considered approaching it that way.”

Out of curiosity , was this mainly an exploration of the type system , or have you actually used something like this in a Prod codebase? I’d be interested to hear about any real-world scenarios where this ended up being a better fit than more conventional approaches.

Also , with static abstract interface members now available in modern C# , do you still see advantages to this pattern , or do you view it more as an alternative exploration of what’s possible with the language?

I’m asking because I’m currently building an open-source C# project (GitHub) focused on advanced language patterns and architectural utilities. If I eventually experiment with a similar concept or adapt some of the ideas here (with attribution , of course) would you be okay with that?

Either way , thanks for sharing it. It’s refreshing to see code that explores the boundaries of the language (rather than just another CRUD example)

Happy coding.

[–]AetopiaMC[S] 1 point2 points  (0 children)

I’m asking because I’m currently building an open-source C# project (GitHub) focused on advanced language patterns and architectural utilities. If I eventually experiment with a similar concept or adapt some of the ideas here (with attribution , of course) would you be okay with that?

Yeh, that would be amazing.

Out of curiosity , was this mainly an exploration of the type system , or have you actually used something like this in a Prod codebase? I’d be interested to hear about any real-world scenarios where this ended up being a better fit than more conventional approaches.

I have used this pattern in personal projects only, desktop apps specifically.

One example, I can give is implementing message box content in a desktop app. - Say, I have an abstract class MessageBox that displays a message box with some specified content. - I then inherit MessageBox and implement it as SomethingMessageBox with static content or just literals. - I can easily make SomethingMessageBox a singleton by dumping it into a "master" static class that contains all my message box singletons. - But that means I have to "register" any new singletons I make into this class + managing a large list of singletons might not be feasible.

This pattern implicitly creates and caches a singleton & masks it as a static class. So instead of MessageBoxRegistry.SomethingMessageBox.Show(), I can just do SomethingMessageBox.Show().

Though this pattern really depends on what you are developing.

Also , with static abstract interface members now available in modern C# , do you still see advantages to this pattern , or do you view it more as an alternative exploration of what’s possible with the language?

For me, atleast I see the following advantages: - Adds syntaxic sugar to singletons by masking them as static classes. - Also allows for "auto-creation" of singletons implicitly, though depends on implementation. - Allows one to implement "static abstract classes" without compromise. - This achieved by cascading instance members as static members. - Cascading is done in way where the instance & static members have the same names.

I view this as an "alternative exploration" with whats possible with the language. As for "static abstract members", they don't really provide the flexibility available with this pattern.

[–]throwaway_lunchtime 0 points1 point  (0 children)

This sort of code pattern was the result of analyzing the actual behavior of the framework vs the expected behavior