ardalis / SmartEnum

A base class for quickly and easily creating strongly typed enum replacements in C#.
MIT License
2.19k stars 170 forks source link

An item with the same key has already been added. When using two sub-classes from abstract SmartEnum class. #274

Open softwarekamal opened 2 years ago

softwarekamal commented 2 years ago

Hello @ardalis, Your library are very awesome and incredible! I got a little problem here when try to accessing enum List property. Actually property works as static and it filled with all enums value of all classes hierarchy not the one that am target!

I think Items dictionary need to be enhancing. Because In my case I got exception "An item with the same key has already been added."

I have following scenario:

  1. Enum Class called : License
  2. two sub-classes one called AppOneLicense:License
  3. second one called AppTwoLicense:License

An enum abstract License class used as base of sealed AppOne, AppTwo classes

Now when AppOne have enum with value of (1 or StandardLicense) And AppTwo have enum with value (1 or TrialLicense)

Exception thrown. Because flags are the same...

Here's implementation you can try it:

public abstract class LicenseEdition : SmartEnum<LicenseEdition, byte>
{
    protected LicenseEdition(string name, byte value) : base(name, value)
    {
    }
}
    public class MyLicenseEditionAppOne : LicenseEdition
    {
   public static readonly MyLicenseEditionAppOne Trial = new MyLicenseEditionAppOne(nameof(Trial ), 1);   // NOTE!!
        public static readonly MyLicenseEditionAppOne Standard = new MyLicenseEditionAppOne(nameof(Standard), 2);
        public static readonly MyLicenseEditionAppOne Professional = new MyLicenseEditionAppOne(nameof(Professional), 3);
        public static readonly MyLicenseEditionAppOne Ultimate = new MyLicenseEditionAppOne(nameof(Ultimate), 4);
        public MyLicenseEditionAppOne(string name, byte value) : base(name, value)
        {
        }
    }
public class MyLicenseEditionAppTwo : LicenseEdition
{
    public static readonly MyLicenseEditionAppTwo Standard = new MyLicenseEditionAppTwo(nameof(Standard ), 1);  // NOTE!!
    public MyLicenseEditionAppTwo(string name, byte value) : base(name, value)
    {
    }
}

That's a problem occurred :sob: The property List need to determine a deal with calling class hierarchy level itself. Not just static base one SmartEnum<>, When I need to access MyLicenseEditionAppOne.List it need to return a list of AppOne enums only not whole SmartEnum<> classes I think...

Interanlly I think List calling _fromName dictionary. which take name as a key! So, If MyLicenseEditionAppOne and MyLicenseEditionAppTwo have same string key (Example Standard name). the Exception thrown then. Maybe you can enhance the _fromName to take a tuple of <(Type, String), TEnum>.

I need to overcome that issue (maybe from my side classes above need to re-design.. to accept same name in dervied enums)

image

softwarekamal commented 2 years ago

At a glance,

If I have following classes:

class BaseClass : SmartEnum<>{

}

class ClassOne : BaseClass{
   public static readonly A = new ClassOne("A", 1);
}

class ClassTwo : BaseClass{
   public static readonly A = new ClassOne("A", 1);
   public static readonly B = new ClassOne("B", 1);
}

When I access to ClassTwo.List I should get A, B When I access to ClassOne.List I should get A only but I got exception (duplicate key)!,

I think the name should not treated as duplicated (the Literial A), because ClassOne are different than ClassTwo But It should be duplicated if BaseClass contains A literal.

Now I don't know what should I do exactly, The SmartEnum.List should treated in target class and their childs only.

If I call ClassTwo.List I should get BaseClass literals and ClassTwo literals only!! not ClassOne literals.

Please @ardalis, Can you help on that to enhance SmartEnum.List or guide me to correct my scenario. Thank you dear!!

elninoisback commented 2 years ago

Why do you want to inherit both from the same base class? SmartEnum, as its name suggests, tries to simulate how enums work, so if basically you cannot have any derivatives of it having the same name or value. Because when given a name or a value, SmartEnum should be able to figure out which object to instantiate. In your case, if 'A' or 1 is passed in, there is ambiguity. To handle that at a design level, the library internally uses a dictionary, which is the most appropriate structure for the job.