C# “枚举”;“继承”;
我在低级命名空间中有一个枚举。我想在“继承”低级枚举的中级命名空间中提供一个类或枚举C# “枚举”;“继承”;,c#,.net,enums,C#,.net,Enums,我在低级命名空间中有一个枚举。我想在“继承”低级枚举的中级命名空间中提供一个类或枚举 namespace low { public enum base { x, y, z } } namespace mid { public enum consume : low.base { } } 我希望这是可能的,或者某种类可以代替enum消费,它将为enum提供一个抽象层,但仍然允许该类的实例访问enum 想法 编辑: 我没有将其切换到类中的常量的原因之
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
我希望这是可能的,或者某种类可以代替enum消费,它将为enum提供一个抽象层,但仍然允许该类的实例访问enum
想法
编辑:
我没有将其切换到类中的常量的原因之一是,我必须使用的服务需要低级枚举。我得到了wsdl和xsd,它们将结构定义为枚举。服务无法更改。简短的回答是“否”。如果您愿意,您可以玩一会儿: 您始终可以执行以下操作:
private enum Base
{
A,
B,
C
}
private enum Consume
{
A = Base.A,
B = Base.B,
C = Base.C,
D,
E
}
但是,它没有那么好用,因为Base.A!=消费
不过,您始终可以这样做:
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);
}
}
公共静态类扩展
{
公共静态T As(这个消费c),其中T:struct
{
return(T)System.Enum.Parse(typeof(T),c.ToString(),false);
}
}
为了在基础和消费之间进行交叉
您还可以将枚举的值强制转换为int,并将它们作为int而不是enum进行比较,但这种方式也很糟糕
扩展方法返回的类型应强制转换为类型T。枚举不是实际的类,即使它们看起来像它。在内部,它们的处理方式与底层类型(默认情况下为Int32)相同。因此,您只能通过将单个值从一个枚举“复制”到另一个枚举,并将它们强制转换为整数来比较它们是否相等来实现此目的。忽略base是保留字这一事实,您无法继承枚举 你能做的最好的事情就是这样:
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),所以可以将一种类型的实例中的值分配给另一种类型的实例。虽然不理想,但它可以工作。这是不可能的。枚举不能从其他枚举继承。事实上,所有枚举实际上都必须从
System.Enum
继承。C#允许语法更改枚举值的底层表示形式,这看起来像是继承,但实际上它们仍然从System.enum继承
有关完整详细信息,请参见第8.5.2节。规范中的相关信息
- 所有枚举必须派生自
System.Enum
- 由于上述原因,所有枚举都是值类型,因此是密封的
正如Pascal所说,您可以使用其他枚举值或常量初始化枚举值,但仅此而已 你可以通过课程实现你想要的:
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;
}
现在,您可以像使用枚举时一样使用这些类:
int i = Consume.B;
更新(更新问题后):
如果将相同的int值指定给现有枚举中定义的常量,则可以在枚举和常量之间进行强制转换,例如:
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;
上面使用int常量类的解决方案缺乏类型安全性。也就是说,你可以发明新的值,而这些值实际上并没有在类中定义。 此外,例如,不可能编写一个将这些类之一作为输入的方法 你需要写信
public void DoSomethingMeaningFull(int consumeValue) ...
然而,在Java的旧时代,当没有可用的枚举时,有一种基于类的解决方案。这提供了一种几乎与枚举类似的行为。唯一需要注意的是,这些常量不能在switch语句中使用
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) { /* ... */ }
// ...
}
您可以在enum中执行继承,但仅限于以下类型。 int,uint,byte,sbyte,short,ushort,long,ulong 例如
我知道这个答案有点晚,但这就是我最后做的:
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
}
另一种可能的解决办法:
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
这就是我所做的。我所做的不同之处在于在“消费”
enum
上使用相同的名称和new
关键字。由于enum
的名称是相同的,您可以无意识地使用它,它将是正确的。另外,你还有智能感知。您只需在设置时手动注意将值从基复制过来并保持同步。您可以在提供代码注释的同时提供帮助。这就是为什么在数据库中存储enum
值时总是存储字符串而不是值的另一个原因。因为如果您使用的是自动分配的递增整数值,这些数值会随着时间的推移而变化
// 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已经提到的)。试图用逻辑来解决这一问题是一种糟糕的做法。如果您有一个基类
具有枚举
,您应该在那里列出所有可能的枚举值
,并且类的实现应该使用它知道的值
例如,假设您有一个基类
BaseCatalog
,它有一个enum ProductFormats
(Digital
,Physical
)。然后你可以有一个MusicCatalog
或BookCatalog
,它可以同时包含Digital
和Physical
产品,但是如果类是ClothingCatalog
,它应该只包含Physical
产品。我还想重载枚举,并创建了和的混合,再加上一些改进。我的解决方案相对于其他解决方案的主要优势:
- 基础int值的自动增量
- 自动命名
CEnum
继承。它具有与.netEnum
类型类似的基本功能:
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;
}
}
}
我知道我来晚了一点,但这是我的两分钱 我们都没事了
// 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
}
}
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;
}
}
}
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 ();
}
}
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
}
// 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
}
// Class in another project
public sealed class SubEnums: BaseEnums
{
private SubEnums()
{}
}