Enum “Inheritance”
我在低级命名空间中有一个枚举。我想在"继承"低级枚举的中级命名空间中提供一个类或枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace low { public enum base { x, y, z } } namespace mid { public enum consume : low.base { } } |
我希望这是可能的,或者可能是某种可以代替枚举使用的类,它将为枚举提供一个抽象层,但仍然允许该类的一个实例访问枚举。
思想?
编辑:我没有将其转换为类中的consts的原因之一是,必须使用的服务需要低级枚举。我得到了wsdls和xsds,它们将结构定义为枚举。无法更改服务。
这是不可能的。枚举不能从其他枚举继承。事实上,所有枚举都必须从
有关完整的详细信息,请参阅CLI规范的第8.5.2节。规范中的相关信息
- 所有枚举必须从
System.Enum 派生 - 由于上述原因,所有枚举都是值类型,因此是密封的
你可以通过课程实现你想要的:
1 2 3 4 5 6 7 8 9 10 11 | 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; } |
现在,您可以使用这些类,就像它们是枚举时一样:
1 | int i = Consume.B; |
更新(更新问题后):
如果为现有枚举中定义的常量指定相同的int值,则可以在枚举和常量之间强制转换,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; |
简短的回答是"否"。如果您需要,您可以玩一点:
你总是可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private enum Base { A, B, C } private enum Consume { A = Base.A, B = Base.B, C = Base.C, D, E } |
但是,它并没有发挥那么大的作用,因为基础。A!=消耗
不过,您始终可以这样做:
1 2 3 4 5 6 7 | 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); } } |
为了在基础和消费之间交叉…
您也可以将枚举的值强制转换为int,并将它们作为int而不是枚举进行比较,但这种情况也很糟糕。
扩展方法返回的类型应为cast类型t。
上面使用带有int常量的类的解决方案缺少类型安全性。也就是说,您可以发明在类中实际上没有定义的新值。此外,例如,不可能编写一个将这些类中的一个作为输入的方法。
你需要写
1 | public void DoSomethingMeaningFull(int consumeValue) ... |
然而,有一个基于类的旧Java的解决方案,当没有枚举可用。这提供了一种几乎类似于枚举的行为。唯一要注意的是,这些常量不能在switch语句中使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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) { /* ... */ } // ... } |
忽略基是保留字这一事实,您不能继承枚举。
你能做的最好的事情就是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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()); } } |
因为它们都是相同的基类型(即:int),所以可以将一个类型的实例中的值赋给另一个类型的实例(即强制转换)。不太理想,但它能起作用。
我知道这个答案有点晚了,但这就是我最终要做的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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 } |
然后我可以做如下的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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) { } |
这就是我所做的。我所做的不同之处是在"消费"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Base Class for balls public class BaseBall { // keep synced with subclasses! public enum Sizes { Small, Medium, Large } } public class VolleyBall : BaseBall { // keep synced with base class! public new enum Sizes { Small = BaseBall.Sizes.Small, Medium = BaseBall.Sizes.Medium, Large = BaseBall.Sizes.Large, SmallMedium, MediumLarge, Ginormous } } |
这是不可能的(正如前面提到的@jaredpar)。试图用逻辑来解决这个问题是一种糟糕的做法。如果您有一个
例如,假设你有一个基类
另一个可能的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
高温高压
枚举不能从其他枚举中脱离,但只能从int、uint、short、ushort、long、ulong、byte和sbyte中脱离。
正如pascal所说,您可以使用其他枚举的值或常量来初始化枚举值,但仅此而已。
枚举不是实际的类,即使它们看起来像这样。在内部,它们被视为其基础类型(默认情况下为Int32)。因此,只能通过将单个值从一个枚举"复制"到另一个枚举,并将它们强制转换为整数来比较它们是否相等来完成此操作。
我还想让Enums过载,并在此页面上创建了"7"的答案和"Merlyn Morgan Graham"的答案的混合,以及一些改进。我的解决方案相对于其他解决方案的主要优势:
- 基础int值的自动增量
- 自动命名
这是一个现成的解决方案,可以直接插入到项目中。它是根据我的需要设计的,所以如果您不喜欢它的某些部分,只需用您自己的代码替换它们。
首先,有一个基本类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 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; } } } |
其次,这里有两个派生的枚举类。所有派生类都需要一些基本方法才能按预期工作。它总是相同的样板代码;我还没有找到将它外包给基类的方法。第一级继承的代码与所有后续级别略有不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 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 (); } } |
这些类已通过以下代码成功测试:
1 2 3 4 5 6 7 8 9 | 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 } |
您可以在枚举中执行继承,但是它仅限于以下类型。int、uint、byte、sbyte、short、ushort、long、ulong
例如。
1 2 3 4 | public enum Car:int{ Toyota, Benz, } |