Related
I have an enum in a low level namespace. I'd like to provide a class or enum in a mid level namespace that "inherits" the low level enum.
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
I'm hoping that this is possible, or perhaps some kind of class that can take the place of the enum consume which will provide a layer of abstraction for the enum, but still let an instance of that class access the enum.
Thoughts?
EDIT:
One of the reasons I haven't just switched this to consts in classes is that the low level enum is needed by a service that I must consume. I have been given the WSDLs and the XSDs, which define the structure as an enum. The service cannot be changed.
This is not possible. Enums cannot inherit from other enums. In fact all enums must actually inherit from System.Enum. C# allows syntax to change the underlying representation of the enum values which looks like inheritance, but in actuality they still inherit from System.enum.
See section 8.5.2 of the CLI spec for the full details. Relevant information from the spec
All enums must derive from System.Enum
Because of the above, all enums are value types and hence sealed
You can achieve what you want with classes:
public class Base
{
public const int A = 1;
public const int B = 2;
public const int C = 3;
}
public class Consume : Base
{
public const int D = 4;
public const int E = 5;
}
Now you can use these classes similar as when they were enums:
int i = Consume.B;
Update (after your update of the question):
If you assign the same int values to the constants as defined in the existing enum, then you can cast between the enum and the constants, e.g:
public enum SomeEnum // this is the existing enum (from WSDL)
{
A = 1,
B = 2,
...
}
public class Base
{
public const int A = (int)SomeEnum.A;
//...
}
public class Consume : Base
{
public const int D = 4;
public const int E = 5;
}
// where you have to use the enum, use a cast:
SomeEnum e = (SomeEnum)Consume.B;
The short answer is no. You can play a bit, if you want:
You can always do something like this:
private enum Base
{
A,
B,
C
}
private enum Consume
{
A = Base.A,
B = Base.B,
C = Base.C,
D,
E
}
But, it doesn't work all that great because Base.A != Consume.A
You can always do something like this, though:
public static class Extensions
{
public static T As<T>(this Consume c) where T : struct
{
return (T)System.Enum.Parse(typeof(T), c.ToString(), false);
}
}
In order to cross between Base and Consume...
You could also cast the values of the enums as ints, and compare them as ints instead of enum, but that kind of sucks too.
The extension method return should type cast it type T.
The solutions above using classes with int constants lack type-safety. I.e. you could invent new values actually not defined in the class.
Furthermore it is not possible for example to write a method taking one of these classes as input.
You would need to write
public void DoSomethingMeaningFull(int consumeValue) ...
However, there is a class based solution of the old days of Java, when there were no enums available. This provides an almost enum-like behaviour. The only caveat is that these constants cannot be used within a switch-statement.
public class MyBaseEnum
{
public static readonly MyBaseEnum A = new MyBaseEnum( 1 );
public static readonly MyBaseEnum B = new MyBaseEnum( 2 );
public static readonly MyBaseEnum C = new MyBaseEnum( 3 );
public int InternalValue { get; protected set; }
protected MyBaseEnum( int internalValue )
{
this.InternalValue = internalValue;
}
}
public class MyEnum : MyBaseEnum
{
public static readonly MyEnum D = new MyEnum( 4 );
public static readonly MyEnum E = new MyEnum( 5 );
protected MyEnum( int internalValue ) : base( internalValue )
{
// Nothing
}
}
[TestMethod]
public void EnumTest()
{
this.DoSomethingMeaningful( MyEnum.A );
}
private void DoSomethingMeaningful( MyBaseEnum enumValue )
{
// ...
if( enumValue == MyEnum.A ) { /* ... */ }
else if (enumValue == MyEnum.B) { /* ... */ }
// ...
}
Ignoring the fact that base is a reserved word you cannot do inheritance of enum.
The best thing you could do is something like that:
public enum Baseenum
{
x, y, z
}
public enum Consume
{
x = Baseenum.x,
y = Baseenum.y,
z = Baseenum.z
}
public void Test()
{
Baseenum a = Baseenum.x;
Consume newA = (Consume) a;
if ((Int32) a == (Int32) newA)
{
MessageBox.Show(newA.ToString());
}
}
Since they're all the same base type (ie: int) you could assign the value from an instance of one type to the other which a cast. Not ideal but it work.
This is what I did. What I've done differently is use the same name and the new keyword on the "consuming" enum. Since the name of the enum is the same, you can just mindlessly use it and it will be right. Plus you get intellisense. You just have to manually take care when setting it up that the values are copied over from the base and keep them sync'ed. You can help that along with code comments. This is another reason why in the database when storing enum values I always store the string, not the value. Because if you are using automatically assigned increasing integer values those can change over time.
// Base Class for balls
public class Ball
{
// keep synced with subclasses!
public enum Sizes
{
Small,
Medium,
Large
}
}
public class VolleyBall : Ball
{
// keep synced with base class!
public new enum Sizes
{
Small = Ball.Sizes.Small,
Medium = Ball.Sizes.Medium,
Large = Ball.Sizes.Large,
SmallMedium,
MediumLarge,
Ginormous
}
}
I know this answer is kind of late but this is what I ended up doing:
public class BaseAnimal : IEquatable<BaseAnimal>
{
public string Name { private set; get; }
public int Value { private set; get; }
public BaseAnimal(int value, String name)
{
this.Name = name;
this.Value = value;
}
public override String ToString()
{
return Name;
}
public bool Equals(BaseAnimal other)
{
return other.Name == this.Name && other.Value == this.Value;
}
}
public class AnimalType : BaseAnimal
{
public static readonly BaseAnimal Invertebrate = new BaseAnimal(1, "Invertebrate");
public static readonly BaseAnimal Amphibians = new BaseAnimal(2, "Amphibians");
// etc
}
public class DogType : AnimalType
{
public static readonly BaseAnimal Golden_Retriever = new BaseAnimal(3, "Golden_Retriever");
public static readonly BaseAnimal Great_Dane = new BaseAnimal(4, "Great_Dane");
// etc
}
Then I am able to do things like:
public void SomeMethod()
{
var a = AnimalType.Amphibians;
var b = AnimalType.Amphibians;
if (a == b)
{
// should be equal
}
// call method as
Foo(a);
// using ifs
if (a == AnimalType.Amphibians)
{
}
else if (a == AnimalType.Invertebrate)
{
}
else if (a == DogType.Golden_Retriever)
{
}
// etc
}
public void Foo(BaseAnimal typeOfAnimal)
{
}
Alternative solution
In my company, we avoid "jumping over projects" to get to non-common lower level projects. For instance, our presentation/API layer can only reference our domain layer, and the domain layer can only reference the data layer.
However, this is a problem when there are enums that need to be referenced by both the presentation and the domain layers.
Here is the solution that we have implemented (so far). It is a pretty good solution and works well for us. The other answers were hitting all around this.
The basic premise is that enums cannot be inherited - but classes can. So...
// In the lower level project (or DLL)...
public abstract class BaseEnums
{
public enum ImportanceType
{
None = 0,
Success = 1,
Warning = 2,
Information = 3,
Exclamation = 4
}
[Flags]
public enum StatusType : Int32
{
None = 0,
Pending = 1,
Approved = 2,
Canceled = 4,
Accepted = (8 | Approved),
Rejected = 16,
Shipped = (32 | Accepted),
Reconciled = (64 | Shipped)
}
public enum Conveyance
{
None = 0,
Feet = 1,
Automobile = 2,
Bicycle = 3,
Motorcycle = 4,
TukTuk = 5,
Horse = 6,
Yak = 7,
Segue = 8
}
Then, to "inherit" the enums in another higher level project...
// Class in another project
public sealed class SubEnums: BaseEnums
{
private SubEnums()
{}
}
This has three real advantages...
The enum definitions are automatically the same in both projects - by
definition.
Any changes to the enum definitions are automatically
echoed in the second without having to make any modifications to the
second class.
The enums are based on the same code - so the values can easily be compared (with some caveats).
To reference the enums in the first project, you can use the prefix of the class: BaseEnums.StatusType.Pending or add a "using static BaseEnums;" statement to your usings.
In the second project when dealing with the inherited class however, I could not get the "using static ..." approach to work, so all references to the "inherited enums" would be prefixed with the class, e.g. SubEnums.StatusType.Pending. If anyone comes up with a way to allow the "using static" approach to be used in the second project, let me know.
I am sure that this can be tweaked to make it even better - but this actually works and I have used this approach in working projects.
I also wanted to overload Enums and created a mix of the answer of 'Seven' on this page and the answer of 'Merlyn Morgan-Graham' on a duplicate post of this, plus a couple of improvements.
Main advantages of my solution over the others:
automatic increment of the underlying int value
automatic naming
This is an out-of-the-box solution and may be directly inserted into your project. It is designed to my needs, so if you don't like some parts of it, just replace them with your own code.
First, there is the base class CEnum that all custom enums should inherit from. It has the basic functionality, similar to the .net Enum type:
public class CEnum
{
protected static readonly int msc_iUpdateNames = int.MinValue;
protected static int ms_iAutoValue = -1;
protected static List<int> ms_listiValue = new List<int>();
public int Value
{
get;
protected set;
}
public string Name
{
get;
protected set;
}
protected CEnum ()
{
CommonConstructor (-1);
}
protected CEnum (int i_iValue)
{
CommonConstructor (i_iValue);
}
public static string[] GetNames (IList<CEnum> i_listoValue)
{
if (i_listoValue == null)
return null;
string[] asName = new string[i_listoValue.Count];
for (int ixCnt = 0; ixCnt < asName.Length; ixCnt++)
asName[ixCnt] = i_listoValue[ixCnt]?.Name;
return asName;
}
public static CEnum[] GetValues ()
{
return new CEnum[0];
}
protected virtual void CommonConstructor (int i_iValue)
{
if (i_iValue == msc_iUpdateNames)
{
UpdateNames (this.GetType ());
return;
}
else if (i_iValue > ms_iAutoValue)
ms_iAutoValue = i_iValue;
else
i_iValue = ++ms_iAutoValue;
if (ms_listiValue.Contains (i_iValue))
throw new ArgumentException ("duplicate value " + i_iValue.ToString ());
Value = i_iValue;
ms_listiValue.Add (i_iValue);
}
private static void UpdateNames (Type i_oType)
{
if (i_oType == null)
return;
FieldInfo[] aoFieldInfo = i_oType.GetFields (BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo oFieldInfo in aoFieldInfo)
{
CEnum oEnumResult = oFieldInfo.GetValue (null) as CEnum;
if (oEnumResult == null)
continue;
oEnumResult.Name = oFieldInfo.Name;
}
}
}
Secondly, here are 2 derived Enum classes. All derived classes need some basic methods in order to work as expected. It's always the same boilerplate code; I haven't found a way yet to outsource it to the base class. The code of the first level of inheritance differs slightly from all subsequent levels.
public class CEnumResult : CEnum
{
private static List<CEnumResult> ms_listoValue = new List<CEnumResult>();
public static readonly CEnumResult Nothing = new CEnumResult ( 0);
public static readonly CEnumResult SUCCESS = new CEnumResult ( 1);
public static readonly CEnumResult UserAbort = new CEnumResult ( 11);
public static readonly CEnumResult InProgress = new CEnumResult (101);
public static readonly CEnumResult Pausing = new CEnumResult (201);
private static readonly CEnumResult Dummy = new CEnumResult (msc_iUpdateNames);
protected CEnumResult () : base ()
{
}
protected CEnumResult (int i_iValue) : base (i_iValue)
{
}
protected override void CommonConstructor (int i_iValue)
{
base.CommonConstructor (i_iValue);
if (i_iValue == msc_iUpdateNames)
return;
if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
ms_listoValue.Add (this);
}
public static new CEnumResult[] GetValues ()
{
List<CEnumResult> listoValue = new List<CEnumResult> ();
listoValue.AddRange (ms_listoValue);
return listoValue.ToArray ();
}
}
public class CEnumResultClassCommon : CEnumResult
{
private static List<CEnumResultClassCommon> ms_listoValue = new List<CEnumResultClassCommon>();
public static readonly CEnumResult Error_InternalProgramming = new CEnumResultClassCommon (1000);
public static readonly CEnumResult Error_Initialization = new CEnumResultClassCommon ();
public static readonly CEnumResult Error_ObjectNotInitialized = new CEnumResultClassCommon ();
public static readonly CEnumResult Error_DLLMissing = new CEnumResultClassCommon ();
// ... many more
private static readonly CEnumResult Dummy = new CEnumResultClassCommon (msc_iUpdateNames);
protected CEnumResultClassCommon () : base ()
{
}
protected CEnumResultClassCommon (int i_iValue) : base (i_iValue)
{
}
protected override void CommonConstructor (int i_iValue)
{
base.CommonConstructor (i_iValue);
if (i_iValue == msc_iUpdateNames)
return;
if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
ms_listoValue.Add (this);
}
public static new CEnumResult[] GetValues ()
{
List<CEnumResult> listoValue = new List<CEnumResult> (CEnumResult.GetValues ());
listoValue.AddRange (ms_listoValue);
return listoValue.ToArray ();
}
}
The classes have been successfully tested with follwing code:
private static void Main (string[] args)
{
CEnumResult oEnumResult = CEnumResultClassCommon.Error_Initialization;
string sName = oEnumResult.Name; // sName = "Error_Initialization"
CEnum[] aoEnumResult = CEnumResultClassCommon.GetValues (); // aoEnumResult = {testCEnumResult.Program.CEnumResult[9]}
string[] asEnumNames = CEnum.GetNames (aoEnumResult);
int ixValue = Array.IndexOf (aoEnumResult, oEnumResult); // ixValue = 6
}
I realize I'm a bit late to this party, but here's my two cents.
We're all clear that Enum inheritance is not supported by the framework. Some very interesting workarounds have been suggested in this thread, but none of them felt quite like what I was looking for, so I had a go at it myself.
Introducing: ObjectEnum
You can check the code and documentation here: https://github.com/dimi3tron/ObjectEnum.
And the package here: https://www.nuget.org/packages/ObjectEnum
Or just install it: Install-Package ObjectEnum
In short, ObjectEnum<TEnum> acts as a wrapper for any enum. By overriding the GetDefinedValues() in subclasses, one can specify which enum values are valid for this specific class.
A number of operator overloads have been added to make an ObjectEnum<TEnum> instance behave as if it were an instance of the underlying enum, keeping in mind the defined value restrictions. This means you can easily compare the instance to an int or enum value, and thus use it in a switch case or any other conditional.
I'd like to refer to the github repo mentioned above for examples and further info.
I hope you find this useful. Feel free to comment or open an issue on github for further thoughts or comments.
Here are a few short examples of what you can do with ObjectEnum<TEnum>:
var sunday = new WorkDay(DayOfWeek.Sunday); //throws exception
var monday = new WorkDay(DayOfWeek.Monday); //works fine
var label = $"{monday} is day {(int)monday}." //produces: "Monday is day 1."
var mondayIsAlwaysMonday = monday == DayOfWeek.Monday; //true, sorry...
var friday = new WorkDay(DayOfWeek.Friday);
switch((DayOfWeek)friday){
case DayOfWeek.Monday:
//do something monday related
break;
/*...*/
case DayOfWeek.Friday:
//do something friday related
break;
}
Enums are not actual classes, even if they look like it. Internally, they are treated just like their underlying type (by default Int32). Therefore, you can only do this by "copying" single values from one enum to another and casting them to their integer number to compare them for equality.
Enums cannot be derrived from other enums, but only from int, uint, short, ushort, long, ulong, byte and sbyte.
Like Pascal said, you can use other enum's values or constants to initialize an enum value, but that's about it.
another possible solution:
public enum #base
{
x,
y,
z
}
public enum consume
{
x = #base.x,
y = #base.y,
z = #base.z,
a,b,c
}
// TODO: Add a unit-test to check that if #base and consume are aligned
HTH
This is not possible (as #JaredPar already mentioned). Trying to put logic to work around this is a bad practice. In case you have a base class that have an enum, you should list of all possible enum-values there, and the implementation of class should work with the values that it knows.
E.g. Supposed you have a base class BaseCatalog, and it has an enum ProductFormats (Digital, Physical). Then you can have a MusicCatalog or BookCatalog that could contains both Digital and Physical products, But if the class is ClothingCatalog, it should only contains Physical products.
The way you do this, if warranted, is to implement your own class structure that includes the features you wanted from your concept of an inherited enum, plus you can add more.
You simply implement equality comparators and functions to look up values you simply code yourself.
You make the constructors private and declare static instances of the class and any subclasses to whatever extent you want.
Or find a simple work around for your problem and stick with the native enum implementation.
Code Heavy Implementation of Inherited Enumerations:
/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceBase
{
//members
protected int _id;
protected string _name;
//constructors
private ServiceBase(int id, string name)
{
_id = id;
_name = name;
}
//onlu required if subclassing
protected ServiceBase(int id, string name, bool isSubClass = true )
{
if( id <= _maxServiceId )
throw new InvalidProgramException("Bad Id in ServiceBase" );
_id = id;
_name = name;
}
//members
public int Id => _id;
public string Name => _name;
public virtual ServiceBase getService(int serviceBaseId)
{
return ALLBASESERVICES.SingleOrDefault(s => s.Id == _id);
}
//implement iComparable if required
//static methods
public static ServiceBase getServiceOrDefault(int serviceBaseId)
{
return SERVICE1.getService(serviceBaseId);
}
//Enumerations Here
public static ServiceBase SERVICE1 = new ServiceBase( 1, "First Service" );
public static ServiceBase SERVICE2 = new ServiceBase( 2, "Second Service" );
protected static ServiceBase[] ALLBASESERVICES =
{
//Enumerations list
SERVICE1,
SERVICE2
};
private static int _maxServiceId = ALLBASESERVICES.Max( s => s.Id );
//only required if subclassing
protected static ServiceBase[] combineServices(ServiceBase[] array1, ServiceBase[] array2)
{
List<ServiceBase> serviceBases = new List<ServiceBase>();
serviceBases.AddRange( array1 );
serviceBases.AddRange( array2 );
return serviceBases.ToArray();
}
}
/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceJobs : ServiceBase
{
//constructor
private ServiceJobs(int id, string name)
: base( id, name )
{
_id = id;
_name = name;
}
//only required if subclassing
protected ServiceJobs(int id, string name, bool isSubClass = true )
: base( id, name )
{
if( id <= _maxServiceId )
throw new InvalidProgramException("Bad Id in ServiceJobs" );
_id = id;
_name = name;
}
//members
public override ServiceBase getService(int serviceBaseId)
{
if (ALLSERVICES == null)
{
ALLSERVICES = combineServices(ALLBASESERVICES, ALLJOBSERVICES);
}
return ALLSERVICES.SingleOrDefault(s => s.Id == _id);
}
//static methods
public static ServiceBase getServiceOrDefault(int serviceBaseId)
{
return SERVICE3.getService(serviceBaseId);
}
//sub class services here
public static ServiceBase SERVICE3 = new ServiceJobs( 3, "Third Service" );
public static ServiceBase SERVICE4 = new ServiceJobs( 4, "Forth Service" );
private static int _maxServiceId = ALLJOBSERVICES.Max( s => s.Id );
private static ServiceBase[] ALLJOBSERVICES =
{
//subclass service list
SERVICE3,
SERVICE4
};
//all services including superclass items
private static ServiceBase[] ALLSERVICES = null;
}
Note that you can use an enum instead of an int as the id, though the subclass will need a separate enum.
The enum class itself can be decorated with all kinds of flags, messages, functions etc.
A generic implementation would reduce a great deal of the code.
Depending on your situation you may NOT need derived Enums as they're based off System.Enum.
Take this code, you can pass in any Enum you like and get its selected value:
public CommonError FromErrorCode(Enum code)
{
Code = (int)Enum.Parse(code.GetType(), code.ToString());
You can perform inheritance in enum, however it's limited to following types only .
int, uint, byte, sbyte, short, ushort, long, ulong
E.g.
public enum Car:int{
Toyota,
Benz,
}
What I am trying to do: I am trying to make component based Objects which can be easly created with custom set type of rules for each component value.
How I am doing it: I have created IComponent interface which each component implements. All components need to be structs, example:
public struct Weight : IComponent
{
int weight;
}
Each Object is defined by just list of components with their values. Then to make it custom set of rules I made ObjectSettings which holds list of generic class ComponentSetup<T> where T : IComponent. ComponentSetup is a class which by reflection gets list of fields in IComponent and pairs them in Dicionary as FieldName and GenerationType for field. For example: for Object "Car" :
Car:
Weight:
weight:
GenerationType: RandomRange
Min: 1200
Max: 1700
For Object "Human":
Human:
Weight:
weight:
GenerationType: NormalDistribution
Expected Value: 70
Variance: 4
For Object "1kg dumbbell":
1kgDumbbell:
Weight:
weight:
GenerationType: Fixed
Value: 1
In order to get generated Objects I used reflection to set values of components compose in List and return as Object.
The problem with this approach: When I want to generate 5k-10k of those Objects it takes way too much time.
My solution so far: I generate semi filled objects(on startup) and store them as prefabs in PrefabManager. They are Objects with components' values set only if their GenerationType is "Fixed" and then only fill values with other types of Generation.
My question: How can I make setting values by reflection faster, if it's not possible then how can I get the same result but faster? I also would like to keep prefab generation on startup because they help me instantiating Objects because I don't need to create whole new object, just copy prefab and fill it, which is faster in my case.
EDIT: Adding example code. I didn't test it however it should be easy to understand what I am trying to do:
namespace Example
{
//ProceduralObject Component intreface
public interface IComponent
{
}
//Example component for procedural object
public struct Weight : IComponent
{
public int weight;
}
//object with procedurally generated components
public class ProceduralObject
{
public List<IComponent> components = new List<IComponent>();
}
public class ProceduralObjectSettings
{
public Dictionary<string,ComponentSetup> ComponentSetups = new Dictionary<string,ComponentSetup>();
public ProceduralObjectSettings()
{
}
public void AddComponent(Type t)
{
//check if added component is assignable from correct interface
if (t.IsAssignableFrom(typeof(IComponent))) ComponentSetups.Add(t.Name,new ComponentSetup(t));
}
//getting ProceduralObject with generated components
public ProceduralObject getGeneratedObject()
{
ProceduralObject newObject = new ProceduralObject();
foreach (var componentSetup in ComponentSetups)
{
newObject.components.Add(componentSetup.Value.getGeneratedComponent());
}
return newObject;
}
}
public class ComponentSetup
{
// Collection of properties of IComponent it represents
public Dictionary<string, IGenerationType> propertyGenerationSettings = new Dictionary<string, IGenerationType>();
// Type of IComponent it represents
public Type t;
public ComponentSetup(Type t)
{
this.t = t;
//Getting all fields of represented IComponent and adding them to propertyGenerationSettings with default GenerationType
var fields = t.GetFields();
for (int i = 0; i < fields.Length; i++)
{
propertyGenerationSettings.Add(fields[i].Name,new EmptyGenerationType());
}
}
//Generating new component with settings
public IComponent getGeneratedComponent()
{
IComponent toReturn = (IComponent)Activator.CreateInstance(t);
var fields = toReturn.GetType().GetFields();
foreach (var property in propertyGenerationSettings)
{
var fieldInfo = fields.First(field => field.Name == property.Key);
toReturn.GetType().SetMemberValue(fieldInfo, property.Value.GetGeneratedValue());
}
return toReturn;
}
}
public interface IGenerationType
{
System.Object GetGeneratedValue();
}
public class EmptyGenerationType : IGenerationType
{
public object GetGeneratedValue()
{
throw new Exception("You can't use EmptyGenerationType");
}
}
public class RandomRangeGenerationType : IGenerationType
{
private double min, max;
public RandomRangeGenerationType(double min, double max)
{
this.min = min;
this.max = max;
}
public object GetGeneratedValue()
{
return null; /* return */
}
}
public class NormalDistributionGenerationType : IGenerationType
{
private double expectedValue, variance;
public NormalDistributionGenerationType(double expectedValue, double variance)
{
this.expectedValue = expectedValue;
this.variance = variance;
}
public object GetGeneratedValue()
{
return null; /* return */
}
}
public class FixedGenerationType : IGenerationType
{
public double value;
public FixedGenerationType(double value)
{
this.value = value;
}
public object GetGeneratedValue()
{
return null;
}
}
public class Example
{
public void Main()
{
Dictionary<string,ProceduralObjectSettings> proceduralObjectsCollection = new Dictionary<string,ProceduralObjectSettings>();
proceduralObjectsCollection.Add("Car",new ProceduralObjectSettings());
proceduralObjectsCollection["Car"].AddComponent(typeof(Weight));
proceduralObjectsCollection["Car"].ComponentSetups["Weight"].propertyGenerationSettings["weight"] = new RandomRangeGenerationType(1200,1700);
proceduralObjectsCollection.Add("Human",new ProceduralObjectSettings());
proceduralObjectsCollection["Human"].AddComponent(typeof(Weight));
proceduralObjectsCollection["Human"].ComponentSetups["Weight"].propertyGenerationSettings["weight"] = new NormalDistributionGenerationType(70,4);
proceduralObjectsCollection.Add("1kgDumbbell",new ProceduralObjectSettings());
proceduralObjectsCollection["1kgDumbbell"].AddComponent(typeof(Weight));
proceduralObjectsCollection["1kgDumbbell"].ComponentSetups["Weight"].propertyGenerationSettings["weight"] = new FixedGenerationType(1);
}
}
}
Reflection is slow, but the execution of delegates is fast. Therefore, if you need to execute things obtained by reflection very often, it is good practise to use reflection to create a delegate and that use that delegate.
Creating the delegate is very simple, as long as you know the type of the property and the type that declares the property. The easiest way to get them is to have these types as generic type parameters in an open generic type. Then, you can close the type at runtime (using MakeGenericType on System.Type) and instantiate the closed generic type using System.Activator.CreateInstance. This is of course costly, but you only need to create objects that describe the properties of your models once and then use it as factories for as many instances as you like without any reflection calls.
Edit: this is how it can look like using properties instead of fields, based on your example code
If you really want to go with fields (which I would encourage you not to do), creating the delegate is slightly more complex (use the expression compiler or emit IL code), but the principal approach remains the same.
public class ComponentSetup
{
// Collection of properties of IComponent it represents
private Dictionary<string, PropertySetter> propertyGenerationSettings = new Dictionary<string, PropertySetter>();
// Type of IComponent it represents
public Type t;
public ComponentSetup( Type t )
{
this.t = t;
//Getting all fields of represented IComponent and adding them to propertyGenerationSettings with default GenerationType
var fields = t.GetProperties();
for(int i = 0; i < fields.Length; i++)
{
var propertySetterType = typeof( PropertySetter<,> ).MakeGenericType( t, fields[i].PropertyType );
var setter = (PropertySetter)Activator.CreateInstance( propertySetterType, fields[i] );
propertyGenerationSettings.Add( fields[i].Name, setter );
}
}
public void SetGenerator<T>( string property, IGenerationType<T> generator )
{
propertyGenerationSettings[property].SetGenerator( generator );
}
//Generating new component with settings
public IComponent getGeneratedComponent()
{
IComponent toReturn = (IComponent)Activator.CreateInstance( t );
foreach(var property in propertyGenerationSettings)
{
property.Value.Set( toReturn );
}
return toReturn;
}
}
internal abstract class PropertySetter
{
public abstract void Set( object target );
public abstract void SetGenerator( object generator );
}
internal class PropertySetter<T, TField> : PropertySetter
{
private Action<T, TField> setter;
private IGenerationType<TField> generator;
public PropertySetter( PropertyInfo property )
{
setter = (Action<T, TField>)property.SetMethod.CreateDelegate( typeof( Action<T, TField> ) );
generator = new EmptyGenerationType<TField>();
}
public override void Set( object target )
{
if(target is T targetObj)
{
setter( targetObj, generator.GetGeneratedValue() );
}
}
public override void SetGenerator( object generator )
{
this.generator = (generator as IGenerationType<TField>) ?? this.generator;
}
}
public interface IGenerationType<T>
{
T GetGeneratedValue();
}
I have a few classes which have some primitive fields and I would like to create a generalized wrapper for them in order to access their fields. This wrapper should somehow contain a reference to the fields of my classes so that I can read/write the values of these fields. The idea is to create a genralized architecture for these classes so that I dont have to write code for each of them. The classes have fields which have a number in them which will be used as an Id to access the fields.
This is some example code that might shed some light on my requirement. What I want in the end is to change the value of some field in the object of Fancy1 class without accessing the object itself but through its wrapper.
class Fancy1
{
public double level1;
public bool isEnable1;
public double level2;
public bool isEnable2;
public double level3;
}
class Fancy2
{
public double level4;
public bool isEnable4;
public double level6;
public bool isEnable6;
public double level7;
}
class FieldWrapper
{
public int id { get; set; }
public object level { get; set; }
public object isEnabled { get; set; }
public FieldWrapper(int id, object level, object isEnabled)
{
this.id = id;
this.level = level;
this.isEnabled = isEnabled;
}
}
class FancyWrapper
{
private Fancy scn;
public FancyWrapper(Fancy scn)
{
if (!(scn is Fancy))
throw new ArgumentException(scn.GetType().FullName + " is not a supported type!");
this.scn = scn;
}
private Dictionary<int, FieldWrapper> fieldLut = new Dictionary<int, FieldWrapper>();
private List<FieldWrapper> _fields { get { return fieldLut.Values.ToList(); } }
public List<FieldWrapper> fields
{
get
{
if (_fields.Count == 0)
{
foreach (System.Reflection.FieldInfo fieldInfo in scn.GetType().GetFields())
{
if (fieldInfo.FieldType == typeof(double))
{
int satId = getIdNr(fieldInfo.Name);
fieldLut.Add(satId, new FieldWrapper(satId, fieldInfo.GetValue(scn), true));
}
}
foreach (System.Reflection.FieldInfo fieldInfo in scn.GetType().GetFields())
{
if (fieldInfo.FieldType == typeof(bool))
{
int satId = getIdNr(fieldInfo.Name);
fieldLut[satId].isEnabled = fieldInfo.GetValue(scn);
}
}
}
return _fields;
}
}
private int getIdNr(string name)
{
System.Text.RegularExpressions.Match m = System.Text.RegularExpressions.Regex.Match(name, #"\d+");
return Int32.Parse(m.Value);
}
}
class Program
{
static void Main(string[] args)
{
Fancy1 fancy = new Fancy1();
fancy.level1 = 1;
fancy.isEnable1 = true;
fancy.level2 = 2;
fancy.isEnable2 = false;
fancy.level3 = 3;
FancyWrapper wrapper = new FancyWrapper(fancy);
wrapper.fields[2].level = 10;
// fancy.level2 should somehow get the value I set via the wrapper
Console.WriteLine(fancy.level2);
Console.ReadLine();
}
}
EDIT: Fancy classes cannot be changed since they are part of an interface!
Depending on how many Fancy classes you are dealing with, you could create an adapter/facade class for each the expose a common interface. eg:
class Fancy1
{
public double level1;
public bool isEnable1;
public double level2;
public bool isEnable2;
public double level3;
}
public class FieldWrapper
{
private Action<double> _levelSetter;
private Func<double> _levelGetter;
private Action<bool> _enableSetter;
private Func<bool> _enableGetter;
public double level { get { return _levelGetter(); } set { _levelSetter(value); }}
public bool isEnabled { get { return _enableGetter(); } set { _enableSetter(value); }}
internal FieldWrapper(Func<double> levelGetter, Action<double> levelSetter, Func<bool> enableGetter, Action<bool> enableSetter)
{
_levelGetter = levelGetter;
_levelSetter = levelSetter;
_enableGetter = enableGetter;
_enableSetter = enableSetter;
}
}
abstract class FancyWrapper
{
public FieldWrapper[] Fields { get; protected set; }
}
class Fancy1Wrapper : FancyWrapper
{
private Fancy1 _fancy1;
public Fancy1Wrapper(Fancy1 fancy1)
{
_fancy1 = fancy1;
this.Fields = new[] { new FieldWrapper(() => fancy1.level1, level => _fancy1.level1 = level, () => _fancy1.isEnable1, enable => _fancy1.isEnable1 = enable),
new FieldWrapper(() => fancy1.level2, level => _fancy1.level2 = level, () => _fancy1.isEnable2, enable => _fancy1.isEnable2 = enable), };
}
}
Or you could invest 5 minutes learning data structures. Consider following example:
var levels = new Dictionary<int, bool>
{
{1, true},
{2, false}
};
if (levels[1])
{
//will run, because level 1 is true
}
if (levels[2])
{
//will not run, because level 2 is false
}
if (levels.ContainsKey(3) && levels[3])
{
//will not run, because dictionary does not contain entry for key 3
}
levels.Add(3, false);
if (levels.ContainsKey(3) && levels[3])
{
//will not run, because level 3 is false
}
levels[3] = true;
if (levels.ContainsKey(3) && levels[3])
{
//will run, because level 3 is true
}
That may seem like what you want, but it really isn't. It is extremely awkward on any number of levels. More specifically, pointers are generally rather "Un-C#-like" and having to know about these numbers defeats the point of having separate classes to begin with.
Think closely about what you want to accomplish. If you're having problems translating it into code, we're here to help. :)
interface IFly<T>
{
T GetMark();
}
public class Bird : IFly<string>
{
public string GetMark()
{
return "Bird";
}
}
public class Plane : IFly<int>
{
public int GetMark()
{
return 123;
}
}
class Program
{
static void Main()
{
IFly<string> bird = new Bird();
IFly<int> plane = new Plane();
Console.WriteLine(bird.GetMark());
Console.WriteLine(plane.GetMark());
Console.ReadKey();
}
}
I would like to replace this
IFly<string> bird = new Bird();
IFly<int> plane = new Plane();
with something like this:
var fly = new List<IFly<T>>
Any suggestions?
This might work:
public interface IFlyRoot { }
interface IFly<T> : IFlyRoot
{
T GetMark();
}
Then you can make a List<IFlyRoot>.
In general case #Steve's answer is the right one. However, depending on your needs you could try using type variance, but it doesn't support value types (int wouldn't work).
Notice the out in interface definition:
interface IFly<out T>
{
T GetMark();
}
Then you are allowed to write:
var list = new List<IFly<object>>();
list.Add(bird);
but it won't work with Plane, where T is a value type (here: int). This solution may not suit your exact needs then.
To get more insight into why variance doesn't work with value types refer to answers of Jon Skeet or Eric Lippert. In short, it's because reference identity should be preserved, but with value types it cannot. A value type would always be boxed first, loosing that identity. That's why it doesn't work automatically. There's not really a clean way around this. One thing you could try is to make Plane class explicitly implement IFly<object> as well:
public class Plane : IFly<int>, IFly<object>
{
public int GetMark()
{
return 123;
}
object IFly<object>.GetMark()
{
return GetMark();
}
}
And add to list:
list.Add(new Plane());
Since IFly and IFly are considered different types by the CLR you will need to establish a more direct relationship between the two, in this case by implementing a non-generic version of the interface IFly. The collection would then store objects as long as they implement this common interface for example:
class Program
{
static void Main()
{
var flyingThings = new ThingsThatFlyCollection();
var bird = new Bird();
var bird2 = new Bird();
var plane = new Plane();
flyingThings.Add(bird);
flyingThings.Add(bird2);
flyingThings.Add(plane);
Console.WriteLine(flyingThings.GetItemWithCast<string>(0).GetMark());
Console.WriteLine(flyingThings.GetItemWithCast<string>(1).GetMark());
Console.WriteLine(flyingThings.GetItemWithCast<int>(2).GetMark());
foreach (var item in flyingThings.GetItemsWithCast<int>())
{
Console.WriteLine(item.GetMark());
}
foreach (var item in flyingThings.GetItemsWithCast<string>())
{
Console.WriteLine(item.GetMark());
}
foreach (var item in flyingThings.GetItemsByType<Bird>())
{
Console.WriteLine(item.GetMark());
}
Console.ReadKey();
}
}
public interface IFly
{
object GetMark();
}
public interface IFly<TMark> : IFly
{
new TMark GetMark();
}
class Plane : IFly<int>
{
public int GetMark() { return 123; }
object IFly.GetMark() { return this.GetMark(); }
}
class Bird : IFly<string>
{
public string GetMark() { return "Bird"; }
object IFly.GetMark() { return this.GetMark(); }
}
class ThingsThatFlyCollection : Collection<IFly>
{
public IFly<TMark> GetItemWithCast<TMark>(int index)
{
var f = this[index] as IFly<TMark>;
if (f == null) { throw new InvalidCastException(); }
return f;
}
public IEnumerable<IFly<TMark>> GetItemsWithCast<TMark>()
{
var items = this.Where(p => p is IFly<TMark>).Cast<IFly<TMark>>();
return items;
}
public IEnumerable<TFlyer> GetItemsByType<TFlyer>() where TFlyer : IFly
{
var items = this.Where(p => p.GetType() == typeof(TFlyer)).Cast<TFlyer>();
return items;
}
}
Keep in mind that upcasting can have some performance implications depending on transaction volume, however is probably negligible for most scenarios.
I have an enum in a low level namespace. I'd like to provide a class or enum in a mid level namespace that "inherits" the low level enum.
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
I'm hoping that this is possible, or perhaps some kind of class that can take the place of the enum consume which will provide a layer of abstraction for the enum, but still let an instance of that class access the enum.
Thoughts?
EDIT:
One of the reasons I haven't just switched this to consts in classes is that the low level enum is needed by a service that I must consume. I have been given the WSDLs and the XSDs, which define the structure as an enum. The service cannot be changed.
This is not possible. Enums cannot inherit from other enums. In fact all enums must actually inherit from System.Enum. C# allows syntax to change the underlying representation of the enum values which looks like inheritance, but in actuality they still inherit from System.enum.
See section 8.5.2 of the CLI spec for the full details. Relevant information from the spec
All enums must derive from System.Enum
Because of the above, all enums are value types and hence sealed
You can achieve what you want with classes:
public class Base
{
public const int A = 1;
public const int B = 2;
public const int C = 3;
}
public class Consume : Base
{
public const int D = 4;
public const int E = 5;
}
Now you can use these classes similar as when they were enums:
int i = Consume.B;
Update (after your update of the question):
If you assign the same int values to the constants as defined in the existing enum, then you can cast between the enum and the constants, e.g:
public enum SomeEnum // this is the existing enum (from WSDL)
{
A = 1,
B = 2,
...
}
public class Base
{
public const int A = (int)SomeEnum.A;
//...
}
public class Consume : Base
{
public const int D = 4;
public const int E = 5;
}
// where you have to use the enum, use a cast:
SomeEnum e = (SomeEnum)Consume.B;
The short answer is no. You can play a bit, if you want:
You can always do something like this:
private enum Base
{
A,
B,
C
}
private enum Consume
{
A = Base.A,
B = Base.B,
C = Base.C,
D,
E
}
But, it doesn't work all that great because Base.A != Consume.A
You can always do something like this, though:
public static class Extensions
{
public static T As<T>(this Consume c) where T : struct
{
return (T)System.Enum.Parse(typeof(T), c.ToString(), false);
}
}
In order to cross between Base and Consume...
You could also cast the values of the enums as ints, and compare them as ints instead of enum, but that kind of sucks too.
The extension method return should type cast it type T.
The solutions above using classes with int constants lack type-safety. I.e. you could invent new values actually not defined in the class.
Furthermore it is not possible for example to write a method taking one of these classes as input.
You would need to write
public void DoSomethingMeaningFull(int consumeValue) ...
However, there is a class based solution of the old days of Java, when there were no enums available. This provides an almost enum-like behaviour. The only caveat is that these constants cannot be used within a switch-statement.
public class MyBaseEnum
{
public static readonly MyBaseEnum A = new MyBaseEnum( 1 );
public static readonly MyBaseEnum B = new MyBaseEnum( 2 );
public static readonly MyBaseEnum C = new MyBaseEnum( 3 );
public int InternalValue { get; protected set; }
protected MyBaseEnum( int internalValue )
{
this.InternalValue = internalValue;
}
}
public class MyEnum : MyBaseEnum
{
public static readonly MyEnum D = new MyEnum( 4 );
public static readonly MyEnum E = new MyEnum( 5 );
protected MyEnum( int internalValue ) : base( internalValue )
{
// Nothing
}
}
[TestMethod]
public void EnumTest()
{
this.DoSomethingMeaningful( MyEnum.A );
}
private void DoSomethingMeaningful( MyBaseEnum enumValue )
{
// ...
if( enumValue == MyEnum.A ) { /* ... */ }
else if (enumValue == MyEnum.B) { /* ... */ }
// ...
}
Ignoring the fact that base is a reserved word you cannot do inheritance of enum.
The best thing you could do is something like that:
public enum Baseenum
{
x, y, z
}
public enum Consume
{
x = Baseenum.x,
y = Baseenum.y,
z = Baseenum.z
}
public void Test()
{
Baseenum a = Baseenum.x;
Consume newA = (Consume) a;
if ((Int32) a == (Int32) newA)
{
MessageBox.Show(newA.ToString());
}
}
Since they're all the same base type (ie: int) you could assign the value from an instance of one type to the other which a cast. Not ideal but it work.
This is what I did. What I've done differently is use the same name and the new keyword on the "consuming" enum. Since the name of the enum is the same, you can just mindlessly use it and it will be right. Plus you get intellisense. You just have to manually take care when setting it up that the values are copied over from the base and keep them sync'ed. You can help that along with code comments. This is another reason why in the database when storing enum values I always store the string, not the value. Because if you are using automatically assigned increasing integer values those can change over time.
// Base Class for balls
public class Ball
{
// keep synced with subclasses!
public enum Sizes
{
Small,
Medium,
Large
}
}
public class VolleyBall : Ball
{
// keep synced with base class!
public new enum Sizes
{
Small = Ball.Sizes.Small,
Medium = Ball.Sizes.Medium,
Large = Ball.Sizes.Large,
SmallMedium,
MediumLarge,
Ginormous
}
}
I know this answer is kind of late but this is what I ended up doing:
public class BaseAnimal : IEquatable<BaseAnimal>
{
public string Name { private set; get; }
public int Value { private set; get; }
public BaseAnimal(int value, String name)
{
this.Name = name;
this.Value = value;
}
public override String ToString()
{
return Name;
}
public bool Equals(BaseAnimal other)
{
return other.Name == this.Name && other.Value == this.Value;
}
}
public class AnimalType : BaseAnimal
{
public static readonly BaseAnimal Invertebrate = new BaseAnimal(1, "Invertebrate");
public static readonly BaseAnimal Amphibians = new BaseAnimal(2, "Amphibians");
// etc
}
public class DogType : AnimalType
{
public static readonly BaseAnimal Golden_Retriever = new BaseAnimal(3, "Golden_Retriever");
public static readonly BaseAnimal Great_Dane = new BaseAnimal(4, "Great_Dane");
// etc
}
Then I am able to do things like:
public void SomeMethod()
{
var a = AnimalType.Amphibians;
var b = AnimalType.Amphibians;
if (a == b)
{
// should be equal
}
// call method as
Foo(a);
// using ifs
if (a == AnimalType.Amphibians)
{
}
else if (a == AnimalType.Invertebrate)
{
}
else if (a == DogType.Golden_Retriever)
{
}
// etc
}
public void Foo(BaseAnimal typeOfAnimal)
{
}
Alternative solution
In my company, we avoid "jumping over projects" to get to non-common lower level projects. For instance, our presentation/API layer can only reference our domain layer, and the domain layer can only reference the data layer.
However, this is a problem when there are enums that need to be referenced by both the presentation and the domain layers.
Here is the solution that we have implemented (so far). It is a pretty good solution and works well for us. The other answers were hitting all around this.
The basic premise is that enums cannot be inherited - but classes can. So...
// In the lower level project (or DLL)...
public abstract class BaseEnums
{
public enum ImportanceType
{
None = 0,
Success = 1,
Warning = 2,
Information = 3,
Exclamation = 4
}
[Flags]
public enum StatusType : Int32
{
None = 0,
Pending = 1,
Approved = 2,
Canceled = 4,
Accepted = (8 | Approved),
Rejected = 16,
Shipped = (32 | Accepted),
Reconciled = (64 | Shipped)
}
public enum Conveyance
{
None = 0,
Feet = 1,
Automobile = 2,
Bicycle = 3,
Motorcycle = 4,
TukTuk = 5,
Horse = 6,
Yak = 7,
Segue = 8
}
Then, to "inherit" the enums in another higher level project...
// Class in another project
public sealed class SubEnums: BaseEnums
{
private SubEnums()
{}
}
This has three real advantages...
The enum definitions are automatically the same in both projects - by
definition.
Any changes to the enum definitions are automatically
echoed in the second without having to make any modifications to the
second class.
The enums are based on the same code - so the values can easily be compared (with some caveats).
To reference the enums in the first project, you can use the prefix of the class: BaseEnums.StatusType.Pending or add a "using static BaseEnums;" statement to your usings.
In the second project when dealing with the inherited class however, I could not get the "using static ..." approach to work, so all references to the "inherited enums" would be prefixed with the class, e.g. SubEnums.StatusType.Pending. If anyone comes up with a way to allow the "using static" approach to be used in the second project, let me know.
I am sure that this can be tweaked to make it even better - but this actually works and I have used this approach in working projects.
I also wanted to overload Enums and created a mix of the answer of 'Seven' on this page and the answer of 'Merlyn Morgan-Graham' on a duplicate post of this, plus a couple of improvements.
Main advantages of my solution over the others:
automatic increment of the underlying int value
automatic naming
This is an out-of-the-box solution and may be directly inserted into your project. It is designed to my needs, so if you don't like some parts of it, just replace them with your own code.
First, there is the base class CEnum that all custom enums should inherit from. It has the basic functionality, similar to the .net Enum type:
public class CEnum
{
protected static readonly int msc_iUpdateNames = int.MinValue;
protected static int ms_iAutoValue = -1;
protected static List<int> ms_listiValue = new List<int>();
public int Value
{
get;
protected set;
}
public string Name
{
get;
protected set;
}
protected CEnum ()
{
CommonConstructor (-1);
}
protected CEnum (int i_iValue)
{
CommonConstructor (i_iValue);
}
public static string[] GetNames (IList<CEnum> i_listoValue)
{
if (i_listoValue == null)
return null;
string[] asName = new string[i_listoValue.Count];
for (int ixCnt = 0; ixCnt < asName.Length; ixCnt++)
asName[ixCnt] = i_listoValue[ixCnt]?.Name;
return asName;
}
public static CEnum[] GetValues ()
{
return new CEnum[0];
}
protected virtual void CommonConstructor (int i_iValue)
{
if (i_iValue == msc_iUpdateNames)
{
UpdateNames (this.GetType ());
return;
}
else if (i_iValue > ms_iAutoValue)
ms_iAutoValue = i_iValue;
else
i_iValue = ++ms_iAutoValue;
if (ms_listiValue.Contains (i_iValue))
throw new ArgumentException ("duplicate value " + i_iValue.ToString ());
Value = i_iValue;
ms_listiValue.Add (i_iValue);
}
private static void UpdateNames (Type i_oType)
{
if (i_oType == null)
return;
FieldInfo[] aoFieldInfo = i_oType.GetFields (BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo oFieldInfo in aoFieldInfo)
{
CEnum oEnumResult = oFieldInfo.GetValue (null) as CEnum;
if (oEnumResult == null)
continue;
oEnumResult.Name = oFieldInfo.Name;
}
}
}
Secondly, here are 2 derived Enum classes. All derived classes need some basic methods in order to work as expected. It's always the same boilerplate code; I haven't found a way yet to outsource it to the base class. The code of the first level of inheritance differs slightly from all subsequent levels.
public class CEnumResult : CEnum
{
private static List<CEnumResult> ms_listoValue = new List<CEnumResult>();
public static readonly CEnumResult Nothing = new CEnumResult ( 0);
public static readonly CEnumResult SUCCESS = new CEnumResult ( 1);
public static readonly CEnumResult UserAbort = new CEnumResult ( 11);
public static readonly CEnumResult InProgress = new CEnumResult (101);
public static readonly CEnumResult Pausing = new CEnumResult (201);
private static readonly CEnumResult Dummy = new CEnumResult (msc_iUpdateNames);
protected CEnumResult () : base ()
{
}
protected CEnumResult (int i_iValue) : base (i_iValue)
{
}
protected override void CommonConstructor (int i_iValue)
{
base.CommonConstructor (i_iValue);
if (i_iValue == msc_iUpdateNames)
return;
if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
ms_listoValue.Add (this);
}
public static new CEnumResult[] GetValues ()
{
List<CEnumResult> listoValue = new List<CEnumResult> ();
listoValue.AddRange (ms_listoValue);
return listoValue.ToArray ();
}
}
public class CEnumResultClassCommon : CEnumResult
{
private static List<CEnumResultClassCommon> ms_listoValue = new List<CEnumResultClassCommon>();
public static readonly CEnumResult Error_InternalProgramming = new CEnumResultClassCommon (1000);
public static readonly CEnumResult Error_Initialization = new CEnumResultClassCommon ();
public static readonly CEnumResult Error_ObjectNotInitialized = new CEnumResultClassCommon ();
public static readonly CEnumResult Error_DLLMissing = new CEnumResultClassCommon ();
// ... many more
private static readonly CEnumResult Dummy = new CEnumResultClassCommon (msc_iUpdateNames);
protected CEnumResultClassCommon () : base ()
{
}
protected CEnumResultClassCommon (int i_iValue) : base (i_iValue)
{
}
protected override void CommonConstructor (int i_iValue)
{
base.CommonConstructor (i_iValue);
if (i_iValue == msc_iUpdateNames)
return;
if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
ms_listoValue.Add (this);
}
public static new CEnumResult[] GetValues ()
{
List<CEnumResult> listoValue = new List<CEnumResult> (CEnumResult.GetValues ());
listoValue.AddRange (ms_listoValue);
return listoValue.ToArray ();
}
}
The classes have been successfully tested with follwing code:
private static void Main (string[] args)
{
CEnumResult oEnumResult = CEnumResultClassCommon.Error_Initialization;
string sName = oEnumResult.Name; // sName = "Error_Initialization"
CEnum[] aoEnumResult = CEnumResultClassCommon.GetValues (); // aoEnumResult = {testCEnumResult.Program.CEnumResult[9]}
string[] asEnumNames = CEnum.GetNames (aoEnumResult);
int ixValue = Array.IndexOf (aoEnumResult, oEnumResult); // ixValue = 6
}
I realize I'm a bit late to this party, but here's my two cents.
We're all clear that Enum inheritance is not supported by the framework. Some very interesting workarounds have been suggested in this thread, but none of them felt quite like what I was looking for, so I had a go at it myself.
Introducing: ObjectEnum
You can check the code and documentation here: https://github.com/dimi3tron/ObjectEnum.
And the package here: https://www.nuget.org/packages/ObjectEnum
Or just install it: Install-Package ObjectEnum
In short, ObjectEnum<TEnum> acts as a wrapper for any enum. By overriding the GetDefinedValues() in subclasses, one can specify which enum values are valid for this specific class.
A number of operator overloads have been added to make an ObjectEnum<TEnum> instance behave as if it were an instance of the underlying enum, keeping in mind the defined value restrictions. This means you can easily compare the instance to an int or enum value, and thus use it in a switch case or any other conditional.
I'd like to refer to the github repo mentioned above for examples and further info.
I hope you find this useful. Feel free to comment or open an issue on github for further thoughts or comments.
Here are a few short examples of what you can do with ObjectEnum<TEnum>:
var sunday = new WorkDay(DayOfWeek.Sunday); //throws exception
var monday = new WorkDay(DayOfWeek.Monday); //works fine
var label = $"{monday} is day {(int)monday}." //produces: "Monday is day 1."
var mondayIsAlwaysMonday = monday == DayOfWeek.Monday; //true, sorry...
var friday = new WorkDay(DayOfWeek.Friday);
switch((DayOfWeek)friday){
case DayOfWeek.Monday:
//do something monday related
break;
/*...*/
case DayOfWeek.Friday:
//do something friday related
break;
}
Enums are not actual classes, even if they look like it. Internally, they are treated just like their underlying type (by default Int32). Therefore, you can only do this by "copying" single values from one enum to another and casting them to their integer number to compare them for equality.
Enums cannot be derrived from other enums, but only from int, uint, short, ushort, long, ulong, byte and sbyte.
Like Pascal said, you can use other enum's values or constants to initialize an enum value, but that's about it.
another possible solution:
public enum #base
{
x,
y,
z
}
public enum consume
{
x = #base.x,
y = #base.y,
z = #base.z,
a,b,c
}
// TODO: Add a unit-test to check that if #base and consume are aligned
HTH
This is not possible (as #JaredPar already mentioned). Trying to put logic to work around this is a bad practice. In case you have a base class that have an enum, you should list of all possible enum-values there, and the implementation of class should work with the values that it knows.
E.g. Supposed you have a base class BaseCatalog, and it has an enum ProductFormats (Digital, Physical). Then you can have a MusicCatalog or BookCatalog that could contains both Digital and Physical products, But if the class is ClothingCatalog, it should only contains Physical products.
The way you do this, if warranted, is to implement your own class structure that includes the features you wanted from your concept of an inherited enum, plus you can add more.
You simply implement equality comparators and functions to look up values you simply code yourself.
You make the constructors private and declare static instances of the class and any subclasses to whatever extent you want.
Or find a simple work around for your problem and stick with the native enum implementation.
Code Heavy Implementation of Inherited Enumerations:
/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceBase
{
//members
protected int _id;
protected string _name;
//constructors
private ServiceBase(int id, string name)
{
_id = id;
_name = name;
}
//onlu required if subclassing
protected ServiceBase(int id, string name, bool isSubClass = true )
{
if( id <= _maxServiceId )
throw new InvalidProgramException("Bad Id in ServiceBase" );
_id = id;
_name = name;
}
//members
public int Id => _id;
public string Name => _name;
public virtual ServiceBase getService(int serviceBaseId)
{
return ALLBASESERVICES.SingleOrDefault(s => s.Id == _id);
}
//implement iComparable if required
//static methods
public static ServiceBase getServiceOrDefault(int serviceBaseId)
{
return SERVICE1.getService(serviceBaseId);
}
//Enumerations Here
public static ServiceBase SERVICE1 = new ServiceBase( 1, "First Service" );
public static ServiceBase SERVICE2 = new ServiceBase( 2, "Second Service" );
protected static ServiceBase[] ALLBASESERVICES =
{
//Enumerations list
SERVICE1,
SERVICE2
};
private static int _maxServiceId = ALLBASESERVICES.Max( s => s.Id );
//only required if subclassing
protected static ServiceBase[] combineServices(ServiceBase[] array1, ServiceBase[] array2)
{
List<ServiceBase> serviceBases = new List<ServiceBase>();
serviceBases.AddRange( array1 );
serviceBases.AddRange( array2 );
return serviceBases.ToArray();
}
}
/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceJobs : ServiceBase
{
//constructor
private ServiceJobs(int id, string name)
: base( id, name )
{
_id = id;
_name = name;
}
//only required if subclassing
protected ServiceJobs(int id, string name, bool isSubClass = true )
: base( id, name )
{
if( id <= _maxServiceId )
throw new InvalidProgramException("Bad Id in ServiceJobs" );
_id = id;
_name = name;
}
//members
public override ServiceBase getService(int serviceBaseId)
{
if (ALLSERVICES == null)
{
ALLSERVICES = combineServices(ALLBASESERVICES, ALLJOBSERVICES);
}
return ALLSERVICES.SingleOrDefault(s => s.Id == _id);
}
//static methods
public static ServiceBase getServiceOrDefault(int serviceBaseId)
{
return SERVICE3.getService(serviceBaseId);
}
//sub class services here
public static ServiceBase SERVICE3 = new ServiceJobs( 3, "Third Service" );
public static ServiceBase SERVICE4 = new ServiceJobs( 4, "Forth Service" );
private static int _maxServiceId = ALLJOBSERVICES.Max( s => s.Id );
private static ServiceBase[] ALLJOBSERVICES =
{
//subclass service list
SERVICE3,
SERVICE4
};
//all services including superclass items
private static ServiceBase[] ALLSERVICES = null;
}
Note that you can use an enum instead of an int as the id, though the subclass will need a separate enum.
The enum class itself can be decorated with all kinds of flags, messages, functions etc.
A generic implementation would reduce a great deal of the code.
Depending on your situation you may NOT need derived Enums as they're based off System.Enum.
Take this code, you can pass in any Enum you like and get its selected value:
public CommonError FromErrorCode(Enum code)
{
Code = (int)Enum.Parse(code.GetType(), code.ToString());
You can perform inheritance in enum, however it's limited to following types only .
int, uint, byte, sbyte, short, ushort, long, ulong
E.g.
public enum Car:int{
Toyota,
Benz,
}