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,
}
I have two constructors which feed values to readonly fields.
public class Sample
{
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
public Sample(int theInt) => _intField = theInt;
public int IntProperty => _intField;
private readonly int _intField;
}
One constructor receives the values directly, and the other does some calculation and obtains the values, then sets the fields.
Now here's the catch:
I don't want to duplicate the
setting code. In this case, just one
field is set but of course there may
well be more than one.
To make the fields readonly, I need
to set them from the constructor, so
I can't "extract" the shared code to
a utility function.
I don't know how to call one
constructor from another.
Any ideas?
Like this:
public Sample(string str) : this(int.Parse(str)) { }
If what you want can't be achieved satisfactorily without having the initialization in its own method (e.g. because you want to do too much before the initialization code, or wrap it in a try-finally, or whatever) you can have any or all constructors pass the readonly variables by reference to an initialization routine, which will then be able to manipulate them at will.
public class Sample
{
private readonly int _intField;
public int IntProperty => _intField;
private void setupStuff(ref int intField, int newValue) => intField = newValue;
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
setupStuff(ref _intField,i);
}
public Sample(int theInt) => setupStuff(ref _intField, theInt);
}
Before the body of the constructor, use either:
: base (parameters)
: this (parameters)
Example:
public class People: User
{
public People (int EmpID) : base (EmpID)
{
// Add more statements here.
}
}
I am improving upon supercat's answer. I guess the following can also be done:
class Sample
{
private readonly int _intField;
public int IntProperty
{
get { return _intField; }
}
void setupStuff(ref int intField, int newValue)
{
//Do some stuff here based upon the necessary initialized variables.
intField = newValue;
}
public Sample(string theIntAsString, bool? doStuff = true)
{
//Initialization of some necessary variables.
//==========================================
int i = int.Parse(theIntAsString);
// ................
// .......................
//==========================================
if (!doStuff.HasValue || doStuff.Value == true)
setupStuff(ref _intField,i);
}
public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
{
setupStuff(ref _intField, theInt);
}
}
Here is an example that calls another constructor, then checks on the property it has set.
public SomeClass(int i)
{
I = i;
}
public SomeClass(SomeOtherClass soc)
: this(soc.J)
{
if (I==0)
{
I = DoSomethingHere();
}
}
Yeah, you can call other method before of the call base or this!
public class MyException : Exception
{
public MyException(int number) : base(ConvertToString(number))
{
}
private static string ConvertToString(int number)
{
return number.toString()
}
}
Constructor chaining i.e you can use "Base" for Is a relationship and "This" you can use for same class, when you want call multiple Constructor in single call.
class BaseClass
{
public BaseClass():this(10)
{
}
public BaseClass(int val)
{
}
}
class Program
{
static void Main(string[] args)
{
new BaseClass();
ReadLine();
}
}
When you inherit a class from a base class, you can invoke the base class constructor by instantiating the derived class
class sample
{
public int x;
public sample(int value)
{
x = value;
}
}
class der : sample
{
public int a;
public int b;
public der(int value1,int value2) : base(50)
{
a = value1;
b = value2;
}
}
class run
{
public static void Main(string[] args)
{
der obj = new der(10,20);
System.Console.WriteLine(obj.x);
System.Console.WriteLine(obj.a);
System.Console.WriteLine(obj.b);
}
}
Output of the sample program is
50 10 20
You can also use this keyword to invoke a constructor from another constructor
class sample
{
public int x;
public sample(int value)
{
x = value;
}
public sample(sample obj) : this(obj.x)
{
}
}
class run
{
public static void Main(string[] args)
{
sample s = new sample(20);
sample ss = new sample(s);
System.Console.WriteLine(ss.x);
}
}
The output of this sample program is
20
Error handling and making your code reusable is key. I added string to int validation and it is possible to add other types if needed. Solving this problem with a more reusable solution could be this:
public class Sample
{
public Sample(object inputToInt)
{
_intField = objectToInt(inputToInt);
}
public int IntProperty => _intField;
private readonly int _intField;
}
public static int objectToInt(object inputToInt)
{
switch (inputToInt)
{
case int inputInt:
return inputInt;
break;
case string inputString:
if (!int.TryParse(inputString, out int parsedInt))
{
throw new InvalidParameterException($"The input {inputString} could not be parsed to int");
}
return parsedInt;
default:
throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
break;
}
}
Please, please, and pretty please do not try this at home, or work, or anywhere really.
This is a way solve to a very very specific problem, and I hope you will not have that.
I'm posting this since it is technically an answer, and another perspective to look at it.
I repeat, do not use it under any condition. Code is to run with LINQPad.
void Main()
{
(new A(1)).Dump();
(new B(2, -1)).Dump();
var b2 = new B(2, -1);
b2.Increment();
b2.Dump();
}
class A
{
public readonly int I = 0;
public A(int i)
{
I = i;
}
}
class B: A
{
public int J;
public B(int i, int j): base(i)
{
J = j;
}
public B(int i, bool wtf): base(i)
{
}
public void Increment()
{
int i = I + 1;
var t = typeof(B).BaseType;
var ctor = t.GetConstructors().First();
ctor.Invoke(this, new object[] { i });
}
}
Since constructor is a method, you can call it with reflection. Now you either think with portals, or visualize a picture of a can of worms. sorry about this.
In my case, I had a main constructor that used an OracleDataReader as an argument, but I wanted to use different query to create the instance:
I had this code:
public Subscriber(OracleDataReader contractReader)
{
this.contract = Convert.ToString(contractReader["contract"]);
this.customerGroup = Convert.ToString(contractReader["customerGroup"]);
this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);
this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);
this.items = new Dictionary<string, Member>();
this.status = 0;
}
So I created the following constructor:
public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup))
{ }
and this method:
private static OracleDataReader getSubReader(string contract, string customerGroup)
{
cmdSubscriber.Parameters[":contract"].Value = contract + "%";
cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";
return cmdSubscriber.ExecuteReader();
}
notes: a statically defined cmdSubscriber is defined elsewhere in the code; My main constructor has been simplified for this illustration.
In case you need to run something before calling another constructor not after.
public class Sample
{
static int preprocess(string theIntAsString)
{
return preprocess(int.Parse(theIntAsString));
}
static int preprocess(int theIntNeedRounding)
{
return theIntNeedRounding/100;
}
public Sample(string theIntAsString)
{
_intField = preprocess(theIntAsString)
}
public Sample(int theIntNeedRounding)
{
_intField = preprocess(theIntNeedRounding)
}
public int IntProperty => _intField;
private readonly int _intField;
}
And ValueTuple can be very helpful if you need to set more than one field.
NOTE: most of the solutions above does not work for structs.
Unfortunately initializing struct fields in a method called by a constructor is not recognized by the compiler and will lead to 2 errors:
in the constructor: Field xxxx must be fully assigned...
in the method, if you have readonly fields: a read-only field cannot be assigned except in a constructor.
These can be really frustrating for example when you just need to do simple check to decide on which constructor to orient your call to.
I'm trying to inherit from a base class but I'm getting an error that I can't figure out. This is the base class:
class Item
{
protected string name;
public Item(string name)
{
this.name = name;
}
}
And this is the inherited class:
class ItemToBuy : Item
{
private int lowPrice;
private int highPrice;
private int maxQuantity;
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity) : base(name)
{
this.lowPrice = lowPrice;
this.highPrice = highPrice;
this.maxQuantity = maxQuantity;
}
}
The issue is this line:
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity) : base(name)
where 'name' is underlined with the error message "An object reference is required for the non-static field, method or property 'Item.name'. If I replace it with a string literal the error message isn't there. What am I doing wrong with inheriting the constructor?
your ItemToBuy class does not have any knowledge of "name".
The way you build the constructor, "name" needs to be a defined string.
Let's say that your constructor looks like this:
class ItemToBuy : Item
{
private int lowPrice;
private int highPrice;
private int maxQuantity;
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity, string name) : base(name)
{
this.lowPrice = lowPrice;
this.highPrice = highPrice;
this.maxQuantity = maxQuantity;
}
}
this will work because the name parameter is defined.
So, you either do it like that or pass a hardcoded value like you did to make it work.
You need to have the name in the ctor of the ItemToBuy class too
public ItemToBuy(string name ,int lowPrice, int highPrice, int maxQuantity) : base(name)
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity) : base(name)
{
this.lowPrice = lowPrice;
this.highPrice = highPrice;
this.maxQuantity = maxQuantity;
}
should be changed to:
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity, string name) : base(name)
{
this.lowPrice = lowPrice;
this.highPrice = highPrice;
this.maxQuantity = maxQuantity;
}
You need to specify the name parameter in the constructor, as per my code above.
you need to receive the name in the constructor of ItemToBuy:
public ItemToBuy(int lowPrice, int highPrice, int maxQuantity,string name) : base(name)
I am getting a compile error in my PC class on the line where I am setting it's inherited STR stat. The compiler error getting is an "Entity.Stat does not contain a constructor that takes 2 arguments. Now I know this not to be the case, because the base Entity class makes the same declarations in its initialization sequence.
If anyone can take a look to see what I'm doing wrong, that would be great. The StatType item is an ENUM that is declared in another file, and is working without issues.
class PC : Entity {
private Class job;
public PC(string name, Race race, Class job, int STR, int DEX, int CON, int WIS, int INT, int CHA){
this.name = name;
this.race = race;
this.job = job;
// This line here is the line giving me difficulties.
this.STR = new Entity.Stat(STR, StatType.Strength);
}
}
public class Entity
{
protected string name;
protected Race race;
protected Stat STR;
protected Stat DEX;
protected Stat CON;
protected Stat WIS;
protected Stat INT;
protected Stat CHA;
public Entity(){ }
public Entity(string name, Race race, int STR, int DEX, int CON, int WIS, int INT, int CHA){
this.name = name;
this.race = race;
this.STR = new Stat(STR, StatType.Strength);
this.DEX = new Stat(DEX, StatType.Dexterity);
this.CON = new Stat(CON, StatType.Constitution);
this.WIS = new Stat(WIS, StatType.Wisdom);
this.INT = new Stat(INT, StatType.Intelligence);
this.CHA = new Stat(CHA, StatType.Charisma);
}
private struct Stat
{
private int id;
private int value;
private int modifier;
public Stat(int value, StatType id)
{
this.id = (int)id;
this.value = value;
this.modifier = ((value - 10) / 2);
}
public int Value
{
get
{
return this.value;
}
set
{
this.value = value;
this.modifier = ((value - 10) / 2);
}
}
public readonly int Modifier
{
get { return this.modifier; }
}
}
}
Your Stat struct is private, meaning it's only visible to the Entity class, not subclasses. Make it protected and it will be visible to the Entity class and any subclasses.
You can't have readonly properties, either, so you're going to get a compiler error on the line public readonly int Modifier as well.
I believe you need to switch Stat to protected:
protected struct Stat
I don't think that the PC class can see the Stat class because it's not visible to it - only to Entity.
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,
}