How to write "smarter" enums in C#

  Рет қаралды 132,942

Nick Chapsas

Nick Chapsas

2 жыл бұрын

Check out my courses: dometrain.com
Use discount code YTUNIT1 at checkout for 15% off
Become a Patreon and get source code access: / nickchapsas
Keep coding merch: keepcoding.shop
Hello everybody I'm Nick and in this video I wanna will show you how you can write smarter enums in C# by using Steve Smith's SmartEnum nuget package. This feature was inspired by Java and how it handles enums and it tries to provide us with a type-safe object-oriented alternative to the classic C# enum.
Give SmartEnum a star: github.com/ardalis/SmartEnum
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
#csharp #dotnet #enum

Пікірлер: 349
@sergeysolomakhin656
@sergeysolomakhin656 2 жыл бұрын
So enum Subscriptions goes in tight binding with discounts. What if another aspect of Subscriptions comes to the scene, for example, user privileges (VIP has full access to every resource, FREE - very limited, etc). Would you put it into the enum as well? I personally think that the concern of enum is a strict hard-coded set of values of a particular entity. That's it. Single responsibility. No business logic.
@brud90
@brud90 2 жыл бұрын
This advice was for BL enums. In that case you can encapsulate all subscription logic in one "enum" class and it's private hierarchy, that allows you to remove all of switch/cases from BL services. In case of another aspect - you should add abstract method in base class, and compiler/intellisence will compel you to realize it in all of inheritors (if it will be a simpe one-liner - it will be a lambda, if not - you can move impementation in separate class/classes, and call it in enums classes)
@HTSCoding
@HTSCoding 2 жыл бұрын
It reminds me when we have to create a "Maybe" class for handling nullable reference type. This is now directly within C#. My guess is that, one day, we have Java-Like enum if this is a really asked feature. From my perspective, I never have a strong need for this use case (while I'm doing DDD all the way).
@mctechcraft7
@mctechcraft7 2 жыл бұрын
I did this myself with attributes, extension methods, and reflection. Nice to know this exists now
@crystalferrai
@crystalferrai 2 жыл бұрын
In C#, make a class with a private constructor and public static members which are instances of that class. Then you have pretty much exactly what you just described from both an implementation and usage point of view. The only difference is you aren't calling it an "enum" in the declaration. The one extra thing you might want to do is override ToString to make it act more like an enum when printing it. You won't be able to switch on it though so maybe that is a deal breaker. You might be able to solve that by adding an implicit cast to an int in the class or something like that. I have not tried it. Maybe this is what that library you are talking about does in the base class. It seems straightforward enough that I would prefer to not include an additional library with my builds just for this feature. Overall, I think that building logic into enums is a bit of an antifeature which can lead to less maintanable code, but that is a whole separate discussion.
@5cover
@5cover 6 ай бұрын
I don't think an implicit cast would work as switch cases require constant expressions.
@Utkarsh191919
@Utkarsh191919 Ай бұрын
Although it is a 2 year old video on a topic as simple as Enums, I still holds good value. Learnt something new after watching this video. Thank you for this, Nick!
@marna_li
@marna_li 2 жыл бұрын
It reminds me of the “Discriminated Unions” proposal of C#. It looks promising: Smart enums with attached data, with pattern matching support. I hope that it will be implemented.
@denys-p
@denys-p 2 жыл бұрын
As an alternative, you could use base class with children classes and use pattern matching over them. Something like public void DooStuff(Animal animal) { switch (animal) { case Dog dog: dog.Bark(); case Cat cat: cat.Meow(); }
@SMT-ks8yp
@SMT-ks8yp 2 жыл бұрын
@@denys-p and what if I give them all a method with similar name and parameters for all enum values, but different implementations? So I could get rid of switch and call it from whatever value an enum variable has. Is it possible? Is it effecient?
@denys-p
@denys-p 2 жыл бұрын
​@@SMT-ks8yp Not sure what you are mean here, but sounds like a Visitor pattern (you can search it and decide if it what you mean or not). It is a slightly different approach. Key differences: 1. With pattern-matching it is easy to add a new method, but hard to add new value into enum/new child class (need to revisit all places where you used it) 2. With Visitor patter it is easy to add a new class ("enum"), but hard to add a new method - you need to revisit all classes ("enums") implementations and add implementation for this method.
@SMT-ks8yp
@SMT-ks8yp 2 жыл бұрын
@@denys-p Hmmm. From what I know about Visitor, it is done through overloading mehtods, and I'm not sure if you can make exact same parameters for all variants. What I mean is probably more like delegate, but tied to enum so it could switch values along with it.
@denys-p
@denys-p 2 жыл бұрын
@@SMT-ks8yp I think it is possible but depends on the specific context. At least, I see no issues with using lambdas/delegates as parameters. Linq works in that way. For example, "Where" receives Func and doesn't care about what happens inside and what variables are captured inside (only in the case of Linq to Objects, Linq to SQL is different and uses Expression instead of Func, despite that syntax looks the same). If it is something that is not inside of nested loops, then probably there are no concerns about performance.
@sealsharp
@sealsharp 2 жыл бұрын
I'm using attributes on enum-values as a way to associate constant data with enum values. Works well with some help of GetAttribute extension methods and a little caching for the reflection part. So i am really hyped for generic attributes
@AShahabov
@AShahabov Жыл бұрын
Thank you for the great explanation. I've come from SmartEnum's GitHub page since I didn't understand how it works.
@adnanal-beda9734
@adnanal-beda9734 2 жыл бұрын
I normally don't watch code tutorial videos, but this channel is really different. This is the third or fourth video I've seen in this channel, and I like it because it shows how to use open-source packages (which I really wished to know about before), instead of just abstract code that would fail very often.
@anonimxwz
@anonimxwz 2 жыл бұрын
I already did my smart enums just using base tools of c# it is actually pretty simple to do
@guilhermemanucci6811
@guilhermemanucci6811 2 жыл бұрын
Nice usage! I have few implementations that I had to do something like, but in my case as The values were fixed, I went to attributes on enums, which I personally found more visual, creating then extension methods do get the values from the attributes by reflection
@AndreasRavnestad
@AndreasRavnestad 2 жыл бұрын
Hm, this might be a good case for source generators. Just write ordinary enums, add some attributes and generate additional helpers and boilerplate code during compilation.
@nickchapsas
@nickchapsas 2 жыл бұрын
That’s actually a really good point!
@mindstyler
@mindstyler 2 жыл бұрын
Disagree. Although I dislike 'smart enums' in general, I still gave this a thought. What you would be doing is creating an enum which you would not ever access / use because you want the smart behaviour. It would kinda bloat your code and confuse other developers / lead to inconsistency.
@twiksify
@twiksify 2 жыл бұрын
@@mindstyler That could be avoided by declearing the enum blueprint as a private inner enum inside a partial class. The source gen is then hooked to the partial class, effectively replacing the visibility of the original blueprint.
@timothywestern6488
@timothywestern6488 2 жыл бұрын
@@twiksify Am I the only one that remembers all the crazy generated code you would see in some classes in 1.1 and early 2.0 days that you literally couldn't touch because one regeneration and it was wiped out?
@mindstyler
@mindstyler 2 жыл бұрын
@@twiksify that would still leave you with 'unused' code and would break encapsulation. That's a big big code smell imo.
@pawetarsaa9904
@pawetarsaa9904 2 жыл бұрын
Wrapping an enum into an object is usually better in medium and bigger projects. It just reduces the number of bugs in the future. If you are using enums, at some point you will be forced to do defensive code against unexpected data (like checking if enum value is not negative) and this defensive code will be repeated across requests. It's good to just wrap it in a value object and make dedicated logic for validation or other stuff.
@twiksify
@twiksify 2 жыл бұрын
This adds coupling between the enum values. I'd much rather use an extension method with a constant lookup table. Composition over inheritance.
@nickchapsas
@nickchapsas 2 жыл бұрын
It adds no coupling. In that context, the enum is the domain concern that owns the values. I know this looks weird and wrong for .NET developers but Java and Kotlin are built with that in mind
@twiksify
@twiksify 2 жыл бұрын
@@nickchapsas You got me wrong. I think that embedding values (discount) is a good idea. However by adding inheritance in the mix you're prohibiting extendability. If you'd like to add another value (region) this can't easily be extended via inheritance.
@nickchapsas
@nickchapsas 2 жыл бұрын
Oh I see what you mean! Yeah it definitely comes with its limitations but at that point we are fighting the language itself
@twiksify
@twiksify 2 жыл бұрын
@@nickchapsas True indeed, anyhow I'd really like to see more comparison like this. C# has lots to learn from other languages. Great video as usual!
@FSEAirboss
@FSEAirboss 2 жыл бұрын
None of the values in this example are static. Anyone that has worked with business/marketing knows that tier names shift and change, and discounts are always being adjusted. Not to mention temporal special tiers at certain times of the year These values will need to be pulled from a data store on creation at the least, and a refresh method most likely as well. I don't know that I see this as a enum type anymore as this is no longer meta, but real data. Perhaps the definition needs to change, but to me enums are still a way to remove magic numbers from the codebase. Still, liked to video and the thought that it invokes.
@LucHeartVR_
@LucHeartVR_ 2 жыл бұрын
I've been searching for this for so long!
@tiefseesurfer
@tiefseesurfer 2 жыл бұрын
I never knew about java and its capabilities for enums, but i had a similar requirement for c# and enums. So I did just implement Atrributes. And my C# enums are still enums but with extended capabilities/values
@BrettFleming
@BrettFleming 2 жыл бұрын
This is the correct way to deal with enums. Use attributes to tag useful information, and extension methods to get the information back from the enum. And with the new code generation features you can easily drop the reflection aspects and generate the extension methods from the enum attributes at compile time.
@josiahtmahachi7291
@josiahtmahachi7291 Жыл бұрын
This sounds interesting 👍🏿. May I please have an example, if you don't mind?
@dbarr49
@dbarr49 2 жыл бұрын
So it sounds like the main use case for this is if the data is always constant like with your planet enum example. Very interesting, I didn't even know you could do that with Java enums. :P lol
@adamodimattia
@adamodimattia 2 жыл бұрын
Java doesn’t have properties, they haven’t invented it yet :) good one :) On the other hand I wish C# had emums not only like Java, but more like in Rust - there’s the enums masterpiece.
@Time21
@Time21 2 жыл бұрын
Thank you Nick, that was an insightful video.
@superpcstation
@superpcstation 2 жыл бұрын
Speaking of jetbrains, can you do a video on their new IDE called fleet?
@timothywestern6488
@timothywestern6488 2 жыл бұрын
Yeah, I love that he says it looks like Rider, when I see Rider, I think it looks like IntelliJ (as did WebStorm and RubyMine I think and every other ide because intelliJ I think came first.)
@adrulb
@adrulb 2 жыл бұрын
@@timothywestern6488 Their IDEs are all based on the IntelliJ source.
@nickchapsas
@nickchapsas 2 жыл бұрын
I’ve been harassing them for access at the NDC Oslo conference so if I am lucky to get in, I will.
@srivathsaharishvenk
@srivathsaharishvenk 2 жыл бұрын
For those who don't like to inherit to do Discriminated unions or smart enums like this, there is Language-ext package which has Union attribute that does the same thing by generating code on file save. Discriminated union should come soon in c#. It will avoid allocations as well as they will use structs
@34823ehwe6w
@34823ehwe6w 2 жыл бұрын
Keep up the good work my guy, appreciate your effort 👌 💪
@jalia1998
@jalia1998 2 жыл бұрын
I Love this! I think it's amazing, Thanks so much for sharing!
@JohnAlexiou
@JohnAlexiou 2 жыл бұрын
I have done this many times using custom attributes (akin to the [Descrition] attribute you see often). Make an attribute that takes a nice name and a discount and with a simple extension method, you can retrieve this information for any Subscription value.
@Lammot
@Lammot 2 жыл бұрын
There is an example of this called enumeration classes in eshop on containers. Basically protected constructor being called via public property + rewritten tostring and equality checks.
@BuggaNoia
@BuggaNoia 2 жыл бұрын
I solve your use case with extensions for the enum. I like indeed the C# enums over Java enums, because they are smaller on stack.
@vmakharashvili
@vmakharashvili 2 жыл бұрын
Thank you. Very helpful!
@reosfire
@reosfire 2 жыл бұрын
One more cool thing in java is that you can use 'lambda' as an interface with one method. And that constructor can be used as 'lambda' that returns a new object. Sometimes I want it in c#
@nickchapsas
@nickchapsas 2 жыл бұрын
Yeah that’s pretty nice as well
@aher5875
@aher5875 2 жыл бұрын
I just love your Greeklish accent, man. Great content too.
@ArgenisVillarroel
@ArgenisVillarroel 2 жыл бұрын
Every time the patreon grows more, congratulations
@joshman1019
@joshman1019 2 жыл бұрын
C#'s extension methods and value converters have always worked well for me in these scenarios. Especially with data bindings.
@nickchapsas
@nickchapsas 2 жыл бұрын
Yeah but I’m not a fan of wasting memory
@KasperSOlesen
@KasperSOlesen 2 жыл бұрын
At a company I worked a few years ago we also wanted ENUMs to be smarter... not actually to be able to add logic to them, but mainly make them easier to work with for APIs. If you use an ENUM for DTO classes in an API, and often you end up doing this, the problem is even a minor change to one of these ENUMs will arguably leave you having to create a new API route that utilizes this updated ENUM as it is a breaking change just to update an ENUM. But a solution to this, is actually part of what this SmartENUM does. That it is just a setup with a value and a name for the value. The newest version of the class makes it easier to use the class in code as you can reference all the properties of it, using the static properties that reference what would normally be a locked value in the ENUM. The advantage being, say the consumer of the API is using an older version of the ENUM not having the new... say FreePlus value of the ENUM, it would still be possible to consume as the classes constructor still accepts it to be constructed with a value and name for this otherwise unknown value. Which would make it possible to stick to the current API route and adding a minor, non-breaking, update to it that the consumers can update to when they are ready to do so, but everything will (or at least should) keep working until they do.
@paulbaker78
@paulbaker78 2 жыл бұрын
Great content as always. I already have a place i want to use this!
@davidwilliss5555
@davidwilliss5555 2 жыл бұрын
Another thing that I've done for years is to add the Description attribute to my enum values. Then I have an extension method that takes an enum and gets the description attribute value or if there isn't one, just ToString()s the enum. It's not real efficient, but it works.
@nickchapsas
@nickchapsas 2 жыл бұрын
Yeah that can really create a performance hit for your app
@andreirosu3450
@andreirosu3450 Жыл бұрын
Hi Nick, It seems when we add more than 4 instances of the "public static readonly Subscription X = new() " that will allocate double the memory. Is there any way to trim that or specify the inital capacity? Thanks!
@Wi11daThri11
@Wi11daThri11 Жыл бұрын
@6:01 "By the way, for context, Java doesn't have properties -- they haven't invented that yet." I love that subtle shade that Nick is throwing at Java! lol =D
@Krakkk
@Krakkk 2 жыл бұрын
The biggest drawback of this approach it's you can't use this in switch. You can always expend on Enum using extension methods, but still it's not solving every issue, the biggest one is - you can't implement interfaces.
@nickchapsas
@nickchapsas 2 жыл бұрын
You actually can using switch expressions with pattern matching
@Krakkk
@Krakkk 2 жыл бұрын
A yes, i forgot about it.
@adamquintana1719
@adamquintana1719 2 жыл бұрын
Steve Smith has some examples of this in his Github repo. But IMO, the pattern matching experience could be better. I think he is just limited by the language.
@steve-ardalis-smith
@steve-ardalis-smith 2 жыл бұрын
Switches are code smells in OO languages. Ideally if you need them, you should only have one of them, in a factory, which then returns an appropriate instance of an object. One switch is fine, but when they start to duplicate they become a maintenance nightmare because any extension or change in behavior must be applied to every switch.
@saniel2748
@saniel2748 2 жыл бұрын
@@steve-ardalis-smith C# is not pure OO language and has a lot of purposes. Switches are great for performance oriented code Also I always thought you use enums when you do know with at least 50% certeinty that you won't need to extend it
@sagielevy
@sagielevy 10 ай бұрын
I wonder if we'll ever get the associated type support in c# like in Swift, where each enum case can have its own data type and each can be different. This combined with good pattern matching support makes enum and exhaustive switch cases an amazingly declarative way to program.
@Kingside88
@Kingside88 2 жыл бұрын
You can also use extension methods. I would not recommend to use this kind of packages because only you know about it and other developers must dig in these package if they want to do some changes
@prasadhkumarjadhav4066
@prasadhkumarjadhav4066 2 жыл бұрын
i love SmarEnum and using it in my solutions it prevents the boxing on enums, only thing was I wasn't able to do was to set an optional parameter to it when used as a method parameter
@dungimon1912
@dungimon1912 Жыл бұрын
Great video as always, and great package .... but I learnt something unexpected here, and that is you can represent a double without the leading 0, for example .25 instead of 0.25. Haha, how did I not know that!
@TarekFaham
@TarekFaham 2 жыл бұрын
The real value is when you can load such mapping between the enum codes and the related properties from the database. There is no big value if you are hard-coding such mapping.
@hroch12345
@hroch12345 2 жыл бұрын
Thanks for the video. Heard about 'smart' enums at Java few years ago. But think that important is how enums is viewed by Java and C# creators. At C# is just for easier life while working with set of numbers. At Java it is 'regular' class with pre-defined instances. At C# can just create struct if want to group few properties together and define constant fields at struct. Like System.Drawing.Size. It wraps two numbers Width and Height. Plus it has special filed Empty which returns size with zero values. So what is actually added value by your class, except to confuse the enemy (viewer your code)?
@kiwiproductions4510
@kiwiproductions4510 2 жыл бұрын
I was thinking that most of what his complaint is can be solved with a structure as well. The benefit of a structure is that it is a value type. Only downside I see with a structure vs enum is that the structure cannot be used in a switch (as far as I know or could figure out). However, the SmartEnum class doesn't solve that either - neither structures nor switches can be used in the case statements of a switch. You can get around the switch limitation by using a Dictionary with the struct as a key or the SmartEnum. You can also just use a regular enum with a Dictionary as the key as well. So then the question is there a hit on performance (such as on Dictionary lookups) or memory when using a SmartEnum that is a full class object over a structure that is a value type? The biggest benefit I can see of the SmartEnum is that there is a large amount of boiler plate it handles for you instead of you having to write your own in the struct. Such as you automatically get a readonly Name string property and a Value property. Additionally it handles overriding Equals for you so that comparison is always done on the Value property. Looking at the source code there is some other niceties as well...such as while the default type for Value is int, you can also specify more than just numbers for the Value type. The Value type just has to implement IEquatable and IComparable. To specify type, you do something like "class MySmartEnum : SmartEnum" (or whatever type you want for Value as long as that other type implements the required interfaces). Other niceties seem to be the FromName that does a dictionary lookup based on the string you pass in. This part right here is probably orders of magnitude better than Enum.Parse which takes a heavy hit on performance due to the nature of reflection. So basically, what this boils down to (as far as I can tell): option A) you write structures to handle the stuff an enum can't handle in C#, but for each of these structures you have to write your own Equals and other helper methods, over and over again for each different structure type (cause the structure cannot inherit from another structure). It can implement Interfaces, but you still have to write all the code for each of Interface methods / properties. This falls into the DRY territory. option B) use SmartEnums that provides a bunch of boiler plate functionality for you so you aren't repeating yourself over and over, and then you only write the code that is special and unique to each SmartEnum you write. Some final thoughts: 1) While SmartEnum seems nice, you can't do a [Flags] enum with it (as far I can tell). 2) Because it uses a dictionary for FromValue, the value should be unique. With enums, you can have multiple entries point to the same value - course you might code analysis warnings / errors doing so, but it's still perfectly legal C# code. You can also do something similar with structures. 3) Not sure how they do it (cause I didn't dig to deep into their code), but you can do something like: MySmartEnum e = (MySmartEnum)1;
@ezsanz7283
@ezsanz7283 2 жыл бұрын
You can use reflection to get the constant's ordinal (in your example) And extension methods when you don't use fields for enum constant, or when you should use dinamical data, dictionaries, db, etc.... and with it isn`t necessary recreate the enum's behavior in a class (base int, flag, class Enum methods, ordinal, etc.) [enum is struct or data variable && class is a data's object/reference]]
@nickchapsas
@nickchapsas 2 жыл бұрын
I prefer to not destroy my app’s performance with pointless reflection usage and tons of unnecessary allocations
@ezsanz7283
@ezsanz7283 2 жыл бұрын
It's a suggestion ... doesn't affect performance, depending on how you useit.... I'd say that the complaint is outdated And your example is a "pointless" code... --but the cuestion is: "pointless" f whom? I'm willing accept ur code expressions, even though with ENUM you have much more performance and better behavior, possibilities, development and so on, without doing anything. When you need extra data you have many ways to get it, and depends your scenary is "pointless" or not
@guilla5
@guilla5 2 жыл бұрын
Which is the main difference between this and making a named tuple that would contain all this information? Being able to consume it as a class as well as having it in one place? Just asking to see if I understood what you were trying to convey.
@alirezanet
@alirezanet 2 жыл бұрын
I did the same thing using Attributes and Extension methods in a few projects. but this still could be a better option because it doesn't use reflection.
@NhanNguyen-ei7tr
@NhanNguyen-ei7tr 2 жыл бұрын
Attributes for Enum is much better for readability.
@protox4
@protox4 2 жыл бұрын
Just add a source generator for those attributes, no more reflection at runtime! ;)
@laurentiudiaconu9840
@laurentiudiaconu9840 2 жыл бұрын
It's basically a small part of how discrimated unions in F# are represented in IL.
@ernest1520
@ernest1520 2 жыл бұрын
Does it actually still hold today when we have record types available? Why not just use records for this kind of stuff (which is what I've been doing now) and let the language do its magic?
@wh33lers
@wh33lers 2 жыл бұрын
Thanks for sharing
@shioli3927
@shioli3927 2 жыл бұрын
In kotlin they took this even further. With sealed classes. Basically enums but the values are classes. Pretty neat for API responses and such, you can group together your Success result, Error result, Loading state and what not without having to shove everything into one response object and have half of the object be null, but instead you are able to group completely different objects. Not sure what made them call it a sealed class though, that part is a mistery.
@nickchapsas
@nickchapsas 2 жыл бұрын
Kotlin is lovely. I think I need to make a video at some point about why I like Kotlin so much and how it "completes" C# for me
@ElvenEatos
@ElvenEatos 2 жыл бұрын
Althoght I must say, the price is supprisingly high for not so long block of content (especialy when you are non-hero to hero type of a guy :), as I have been watching your videos here for quite some time, I would concider it a method to show you my support. And also I'm corious as this is your first one.
@VamsiKrishna-yt5hi
@VamsiKrishna-yt5hi 2 жыл бұрын
Hi, can you take up the topic of weak references and how to work with them in your next?
@stijnvanhoecke4753
@stijnvanhoecke4753 2 жыл бұрын
Done this kind of behaviour for many years already with custom attributes and extension methods... with lambdas to indicate which property filter I want to find enum values on... :)
@sps014
@sps014 2 жыл бұрын
I use record to create DU. public interface IShape { public record Square(int side):IShape; public record Rect(int l,int w):IShape; } IShape c= new IShape.Rect(5,6); //Or assign other c=new IShape.Circle(6); //Matching if(c is IShape.Rect r) WriteLine(r.l*r.w);
@sonicdev599
@sonicdev599 2 жыл бұрын
Wow this looks natural and awesome. We could also use record struct for preventing memory allocations for types. Great.
@natrixnatrix
@natrixnatrix 2 жыл бұрын
Records where my first thought too but I have never thought of putting them in an interface like that. I usually create an abstract record but your way looks a lot better.
@bearpro
@bearpro 2 жыл бұрын
Сколько костылей ООПшники должны изобрести, прежде чем прийти наконец к размеченным объединениям?
@user-tk2jy8xr8b
@user-tk2jy8xr8b 2 жыл бұрын
Man, was about to write about ADTs when saw your comment
@OLApplin
@OLApplin 2 жыл бұрын
Enums in Java can even have abstract method that needs to be implemented in a body for each enum constant!
@RandalGJunior
@RandalGJunior 2 жыл бұрын
Doesn't it do compromise memory allocation? Classes go to the Heap and enuns go to stack, right? Perhaps a extension with decorators approach wouldn't be better? Or the reflections could consume all the benefits?
@nickchapsas
@nickchapsas 2 жыл бұрын
It does but this isn’t garbage collectible memory because you’re dealing with static readonly fields so even tho the memory will be allocated, it’s not memory that can cause GC pressure, which is what we don’t want
@Max-mx5yc
@Max-mx5yc 2 жыл бұрын
what theme are you using for intellij idea?
@the-niker
@the-niker 2 жыл бұрын
That's awkward I actually made this about 10 years ago, the exact same name SmartEnum, same idea very similar implementation with some extras like ability to add enum values dynamically at runtime (database based enums). Sadly it was for a proprietary codebase.
@frossen123
@frossen123 2 жыл бұрын
How does this work with bitflags? i would also use the singular Subscription instead of the plural to tell that you will only have one enum value instead of multiple like with flags
@alexmacra4746
@alexmacra4746 10 ай бұрын
Can we have in our enum like public enum Test { auto-draft,mec-tickets and so on} ? I need to get these type of values from enum
@jegtugado3743
@jegtugado3743 2 жыл бұрын
Ardalis libraries and templates look really convenient
@cliffordnelson8454
@cliffordnelson8454 2 жыл бұрын
I have used classes in a similar way. Have used with with Combo boxes, and that way the behavior is with whatever is selected. Also used for errors where there is additional information returned on how to handle errors, like the message to display to the user.
@kenbrady119
@kenbrady119 2 жыл бұрын
I've achieved equivalent "extension" of C# enums using extension methods. Yes, enums work as the 'this' parameter of extension methods!
@pdevito
@pdevito 2 жыл бұрын
Love SmartEnums! Use them in all my projects. Jimmy bogard has a good refactoring video using them as well
@timothywestern6488
@timothywestern6488 2 жыл бұрын
the course looks pretty good, I really want to take a look to see if its something I could recommend for new-boots-in-the-code. Can your processor handle American Payment Cards?
@nickchapsas
@nickchapsas 2 жыл бұрын
Yeah I'm using Stripe so any card (that they support) is supported
@lordmetzgermeister
@lordmetzgermeister 2 жыл бұрын
Does this work with dependency injection? Can the constructor get for example a localization service from DIC to localize the friendly name?
@nickchapsas
@nickchapsas 2 жыл бұрын
You should not have logic in there that needs to be computed with dependency injection. That would be a sign of it doing too much and maybe showing that this isn’t the right usecase for the library
@mistermeua
@mistermeua 2 жыл бұрын
Not sure I need that in the majority of cases when I write code at my every day practice. Though it looks sweet, enums have a bit another purpose in c# (in my perspective - of course). And this is smth like a named representation of a number. And that number in used to “mark” something. I'd like to have a separation of concerns. If I need a number wrapper with logic and label - I have class/structure. Like an encapsulation - is wrapping functions and data they use under a single border(function is called method in this case). I do not think I want to overload such a simple thing as enum with additional logic. Because border between enum and class vanishes.
@InshuMussu
@InshuMussu Жыл бұрын
@Nick Thanks for sharing awesome videos like this, I have a question, shouldn't we keep Enum simple instead of putting business logic in it, I am sure by time enum will grow up and end up with a huge file, and my second point is that enum will also expose those methods to the other class where we don't require those methods. we can handle such scenarios with other techniques so why Enum!, please share if I am missing something?
@henriquemfernandes1
@henriquemfernandes1 2 жыл бұрын
Its a really neat trick. But i think if we have a really big enum, and for each of the values, One result, i think its mutch easyer and Faster to use enum and dictionary and getting the result just by reading the dictionary.
@raztubes
@raztubes 2 жыл бұрын
I could see the potential for some nasty code here. Honestly, I say leave it the way it is, and if you need to, write an extension.
@hoangnguyenm9384
@hoangnguyenm9384 2 жыл бұрын
It looks good. How's about the Flag enum when we are using the SmartEnum ?
@zoltanzorgo
@zoltanzorgo 2 жыл бұрын
Or something like this, as enum values are nothing but fileds anyway. But I ended up not using enums at all when there is a need to attach anything more than a description to them. Simply because such values (subscriptions and discount are a great example) are rarely things that are not pat of a more complex business model: they tend to change some property, or their cardinality. Thus making them not suitable to be hardcoded. It depends, of course, but one should really consider when to expect more from enums as they currently provide. public abstract class EnumLike where T: EnumLike { public int Value { get; private set; } private EnumLike SetValue(int value) { Value = value; return this; } public override string ToString() { return maps.Value[this]; } private static Lazy maps = new Lazy(PrepareMap); private static IDictionary PrepareMap() => typeof(T) .GetFields(BindingFlags.Public | BindingFlags.Static) .Where(x => x.DeclaringType == typeof(T)) .Select((x, i) => new { x, i }) .ToDictionary(x => (object)((T)x.x.GetValue(null)).SetValue(x.i), x => x.x.Name); } public sealed class Subscription: EnumLike { public static readonly Subscription Free = new Subscription(0); public static readonly Subscription Pro = new Subscription(.25); public static readonly Subscription Vip = new Subscription(.5); public double Discount { get; } private Subscription(double discount) { Discount = discount; } } void Main() { Subscription proSubscription = Subscription.Pro; Console.WriteLine($"Discount for {proSubscription} subscription is {proSubscription.Discount} "); }
@johnnyb6359
@johnnyb6359 2 жыл бұрын
Great video
2 жыл бұрын
Using it in all our projects. Only problem we have with it is with Swagger which cannot read the static properties, so enums are better in creating and maintaining API documentation
@nickchapsas
@nickchapsas 2 жыл бұрын
You can write a custom converter that reads the object and spits the value out
@8ytan
@8ytan 2 жыл бұрын
I'm guessing that comparisons between values using the 'is' keyword would not be possible with these enums?
@michelchaghoury9629
@michelchaghoury9629 Жыл бұрын
I would like to see more Difference betwwen Java and C# videos, as an advanced Java/Spring developer i found interest in C#/NET and want to learn more on the language but do not want to start from Zero, like understanding variable or loop, but I need somerhing straight forward like this video, kindly can you take it into consideration? or make 2 videos 'C# from Java Devs' and 'NET for Spring Devs' ?
@amrelsher4746
@amrelsher4746 2 жыл бұрын
Cool Nick ,what if i need to add another type of Subscription that not has nothing to do with discounts .
@alexgjo3132
@alexgjo3132 2 жыл бұрын
hey Nick, I've been doing the same things in C# that you did in Java just by using attributes and extensions methods. I don't use any external packages.
@nickchapsas
@nickchapsas 2 жыл бұрын
You are missing out on a lot of performance with that approach
@DF-ov1zm
@DF-ov1zm 11 ай бұрын
Java way looks good, I hope C# will support this eventually. But for now I just use custom attributes for pretty much the same.
@PinheiroJaime
@PinheiroJaime 2 жыл бұрын
The important part of using enum - switch and pattern matching - you left aside. What smart enum does is pretty simple to do yourself with records. Regardless of your choice, not sure how you will ensure for a new value on enum to check all switches in your code...
@nickchapsas
@nickchapsas 2 жыл бұрын
Records are classes unless specified otherwise so if you do it with records and you do it wrong you will get some really nasty allocations. The outcome would be the same but smart enums are more feature rich
@somnion5094
@somnion5094 2 жыл бұрын
Dude knows what he is talking about. A perfect example is at 6:43.
@dgschrei
@dgschrei 2 жыл бұрын
Enums are meant to provide a more developer friendly way to assign discrete numeric values to things. They also provide stability when persisting values (I can always add to an enum without breaking any of the persisted data) this approach pretty much breaks all of that. If an enum "value" now basically represents multiple properties you break all previously persisted data if you add another value to your "domain representation" since the number of stored values changes. Either that or you need to have a separate actual enum lying around that is used for persistence, at which point the approach is basically back to having an enumn and a class that does the mapping from enum values to instances of the smart enum so you've gained absolutely nothing. So in conclusion: just because Java and by extension Kotlin didn't understand the difference between a class (which is inheritable or preferably composable to extend it with business logic) and a simple named enumeration doesn't mean it's a smart approach to copy these patterns into a language where the designers were well aware of the difference. I'd actually say that is precisely the reason why this proposal didn't make it into the language specification.
@timothywestern6488
@timothywestern6488 2 жыл бұрын
Very interesting elaboration @dgschrei thank you.
@Krakkk
@Krakkk 2 жыл бұрын
"Enums are meant to provide a more developer friendly way to assign discrete numeric values to things" It's almost never a case. Enums are used to have fixed list of given category (sometimes ordered), the numbers assign to them are usually meaningless. "Either that or you need to have a separate actual enum lying around that is used for persistence" It would add no persistance only more potential bugs to worry about. Readonly properties doesn't change persistance.
@dgschrei
@dgschrei 2 жыл бұрын
@@Krakkk you misunderstood me. Basically my point was any time you need to store your "Smartenum" in a database, in XML, transmit it over a network, basically any time your object with a Smartenum property needs to leave your process's memory, you will need to have a second "notsmartenum" so you can actually store/transmit it without saving out unstable data that will break if you change your Smartenum. (if you just serialize out the Smartenum and you add a third property you run into trouble when you load the Smartenum you stored away when the type only had 2 properties) The more I think about Nick's example in particular I end up with the conclusion that the name and discount should really just be saved out to a config file/database and not be in the source code at all. Hard coding these values is basically a violation of the open closed principle. Your code shouldn't need to change because the discount for a subscription changes, or because management wants an additional fourth subscription tier. And I'd actually argue that this principle doesn't only apply to Nick's example but for the vast majority of cases where you would need this "enum but with additional values" pattern. Your code really should just contain the logic necessary to interpret and operate on the data. (i.e. Read in the subscription name and the discount and the logic to apply the discount to the price) and the data itself should be treated like data and that means stored away and read in as needed. Now you could argue: but I know that objects with a smartEnum never need to leave my process so this is fine. But much of good software engineering is about knowing how to avoid to shoot yourself in the foot down the line. And since we all can't know what future requirements might bring the assumption that at some point the data will indeed need to be transmitted is a good safeguard for the future. Especially since needing to change from Smartenum back to normal enum 2 years down the line will likely be a rather involved and annoying refactoring job.
@morten624
@morten624 2 жыл бұрын
@@dgschrei Your whole argument assumes that you have to persist all properties, which then breaks backward compatibility after a change. At my previous job we actually only persisted the name of the 'enum' and then through an ORM extension, it got automatically hydrated as the smart enum instance. For our use case, the experience was much better than with a regular enum.
@MichaelKonovaliuk
@MichaelKonovaliuk 2 жыл бұрын
Ardalis has a lot of cool, little, fancy and helpful staff! I love his Guard and Specification packages
@fabianmitchell9443
@fabianmitchell9443 2 жыл бұрын
Jimmy Bogard wrote about this solution (Enumeration Class) in Los Techies 2012
@nickchapsas
@nickchapsas 2 жыл бұрын
I think he also has a blog post on it since 2008
@br3nto
@br3nto 2 жыл бұрын
How awesome are Java enums!!!
@seika8803
@seika8803 2 жыл бұрын
So what's the benefit of changing an enum as a value type to a class reference type with static class variables to behave as a constant in C#. Seems like some of the benefits of value types are more important such as performance, use of switch statement, etc. Maintainability seems compromised too due to the duplicate code from copying and pasting same class logic (no model or properties changes) to support static var changes. Maybe a struct and/or interface would be just as effective and a more extensible approach.
@nickchapsas
@nickchapsas 2 жыл бұрын
Static readonly fields are only allocated once, which won’t cause any GC pressure, and they don’t need to be copied like value types so performance is actually fine. You can also totally use them on switch both with pattern matching and with switch expressions.
@Myuuiii
@Myuuiii 2 жыл бұрын
You honestly make the most interesting and useful videos
@Tsunami14
@Tsunami14 2 жыл бұрын
Microsoft rejected a language proposal from the legendary Jon Skeet? Unthinkable!
@benjaminboyle3295
@benjaminboyle3295 2 жыл бұрын
Deserializers will create new instances instead of reusing the static read-only instances. This will make comparison using == operator fail.
@nickchapsas
@nickchapsas 2 жыл бұрын
The operator is overloaded and it’s based on the enum value so it will work fine
@mysterio7385
@mysterio7385 2 жыл бұрын
Can you do a tutorial on simple api with authentication using minimal api?
@konstantinta2803
@konstantinta2803 2 жыл бұрын
I would like to have a sort of Rust's algebraic data types in C#
@flyingmadpakke
@flyingmadpakke 2 жыл бұрын
Awesome that you are creating courses Nick! I'll admit, I've never really looked into unit testing and I don't have any structured approach, so I do it differently every time. Will ask if the company can cover the cost ;) Btw, I checked your course site out, looks great! I found that the play-back speed under settings in the top left appears slightly bugged in my chrome browser; The button shows both the initial speed, and whatever speed I set it to at the same time. One last thing, what other courses/topics are you planning on releasing?
@oleksiishytikov9802
@oleksiishytikov9802 2 жыл бұрын
enums in C# are value type, same as int or struct. And it's actually feature because it won't need unboxing when comparing to some values. It's fast, it consumes less memory. It's a good thing.
@nickchapsas
@nickchapsas 2 жыл бұрын
This is actually only partially correct. You see, these are static readonly reference types, so they will only be allocated once and reused. They don't cause memory pressure and won't be allocated multiple times. Enums can get boxed and unboxed. These reference types can't. Also, enums are ints are struct. A struct and an in aren't different types. An Int is a struct.
@oleksiishytikov9802
@oleksiishytikov9802 2 жыл бұрын
@@nickchapsas I should always read my comments before posting, as I'm always forgetting to be nice first! So let me correct myself. Awesome video and awesome ideas! I actually never felt like enums in C# are lacking something, until recently discovered Kotlin :)
@lucya9162
@lucya9162 2 жыл бұрын
Hmm any reason for not using c# attributes to tag your enums with secondary data instead of building up an OOP class structure?
@nickchapsas
@nickchapsas 2 жыл бұрын
Because of performance
@lucya9162
@lucya9162 2 жыл бұрын
@@nickchapsas You mean performance in the sense of needing to catch attribute information for enums to avoid paying the lookup cost each time you access the attribute data?
@Unhelthy235
@Unhelthy235 2 жыл бұрын
What's the special copy being used at 00:04:30 ?
@huferry
@huferry 2 жыл бұрын
I would rather implement the ‘enum’ using a record. And those values can be public static props (factory method, but using props, factory prop :)). At least the reader of my code know what it is made without wondering whtat a SmartEnum is. Usually you’d read at least twice what the base class does..
@abrahamrivera3156
@abrahamrivera3156 2 жыл бұрын
I am not convinced, what is the point of having a smart enum if a well write class can do the job? I think it will be a good point to add to the video. Can you elaborate please?
@amgos
@amgos 2 жыл бұрын
Can't you achieve pretty much the same with a struct containing a private ctor and public static members of that struct type that return the specific instances ? No need for 3rd party lib
@nickchapsas
@nickchapsas 2 жыл бұрын
You wouldn’t achieve the serialisation logic by default you’d have to write all that yourself
@Redok09
@Redok09 2 жыл бұрын
Why not use custom enum attributes? Then just add an extension method to fetch the discount value in the attribute.
Why aspect-oriented programming in C# is pointless
17:02
Nick Chapsas
Рет қаралды 45 М.
What are record types in C# and how they ACTUALLY work
15:36
Nick Chapsas
Рет қаралды 116 М.
The Worlds Most Powerfull Batteries !
00:48
Woody & Kleiny
Рет қаралды 18 МЛН
когда достали одноклассники!
00:49
БРУНО
Рет қаралды 3,5 МЛН
Шокирующая Речь Выпускника 😳📽️@CarrolltonTexas
00:43
Глеб Рандалайнен
Рет қаралды 9 МЛН
Be kind🤝
00:22
ISSEI / いっせい
Рет қаралды 20 МЛН
The Only .NET Scheduler You Should Be Using!
16:38
Nick Chapsas
Рет қаралды 43 М.
How To Create Smart Enums in C# With Rich Behavior
17:31
Milan Jovanović
Рет қаралды 50 М.
8 await async mistakes that you SHOULD avoid in .NET
21:13
Nick Chapsas
Рет қаралды 307 М.
Don't throw exceptions in C#. Do this instead
18:13
Nick Chapsas
Рет қаралды 248 М.
How IEnumerable can kill your performance in C#
11:02
Nick Chapsas
Рет қаралды 112 М.
"Stop Wasting Memory on Strings in C#!" | Code Cop #016
9:20
Nick Chapsas
Рет қаралды 67 М.
the TRUTH about C++ (is it worth your time?)
3:17
Low Level Learning
Рет қаралды 593 М.
Getting Started with Event Sourcing in .NET
37:07
Nick Chapsas
Рет қаралды 42 М.
The Worlds Most Powerfull Batteries !
00:48
Woody & Kleiny
Рет қаралды 18 МЛН