열거 형“상속”
저수준 네임 스페이스에 열거 형이 있습니다. 저수준 열거 형을 "상속"하는 중간 수준 네임 스페이스에 클래스 또는 열거 형을 제공하고 싶습니다.
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
나는 이것이 가능하거나 열거 형 소비를 대체 할 수있는 일종의 클래스가 있기를 바라고 있습니다.
생각?
편집 : 클래스에서 const로 전환하지 않은 이유 중 하나는 내가 사용해야하는 서비스에 저수준 열거가 필요하기 때문입니다. 구조를 열거 형으로 정의하는 WSDL과 XSD를 받았습니다. 서비스를 변경할 수 없습니다.
이건 불가능 해. 열거 형은 다른 열거 형에서 상속 할 수 없습니다. 실제로 모든 열거 형은 실제로에서 상속해야합니다 System.Enum
. C #에서는 구문이 상속처럼 보이는 열거 형 값의 기본 표현을 변경할 수 있지만 실제로는 System.enum에서 상속됩니다.
자세한 내용은 CLI 사양 8.5.2 단원을 참조 하십시오. 사양의 관련 정보
- 모든 열거 형은
System.Enum
- 위의 때문에 모든 열거 형은 값 유형이므로 봉인됩니다.
수업을 통해 원하는 것을 얻을 수 있습니다.
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;
업데이트 (질문 업데이트 후) :
기존 열거 형에 정의 된 것과 동일한 정수 값을 상수에 할당하면 다음과 같이 열거 형과 상수간에 캐스트 할 수 있습니다.
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;
짧은 대답은 '아니요'입니다. 원하는 경우 조금만 재생할 수 있습니다.
항상 다음과 같은 작업을 수행 할 수 있습니다.
private enum Base
{
A,
B,
C
}
private enum Consume
{
A = Base.A,
B = Base.B,
C = Base.C,
D,
E
}
그러나 Base.A! = Consume.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);
}
}
Base와 Consume을 교차하려면 ...
열거 형의 값을 정수로 캐스팅하고 열거 형 대신 정수로 비교할 수도 있지만 그러한 종류의 짜증도 있습니다.
확장 메소드 리턴은 유형 T를 캐스트해야합니다.
정수 상수가있는 클래스를 사용하는 위의 솔루션에는 형식 안전성이 없습니다. 즉, 실제로 클래스에 정의되지 않은 새로운 값을 발명 할 수 있습니다. 또한 예를 들어 이러한 클래스 중 하나를 입력으로 사용하는 메소드를 작성할 수 없습니다.
당신은 쓸 필요가있을 것입니다
public void DoSomethingMeaningFull(int consumeValue) ...
그러나 사용 가능한 열거 형이 없었던 Java의 클래스 기반 솔루션이 있습니다. 이것은 거의 enum-like 행동을 제공합니다. 유일한 경고는 이러한 상수를 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) { /* ... */ }
// ...
}
base가 예약어라는 사실을 무시하면 enum의 상속을 수행 할 수 없습니다.
가장 좋은 방법은 다음과 같습니다.
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)이기 때문에 한 타입의 인스턴스에서 다른 타입으로 캐스팅 된 값을 할당 할 수 있습니다. 이상적이지는 않지만 작동합니다.
나는이 답변이 늦다는 것을 알고 있지만 이것이 내가 한 일입니다.
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 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)
{
}
이것이 내가 한 일입니다. 내가 다르게 한 것은 new
"소비"에 동일한 이름과 키워드를 사용하는 것 enum
입니다. 의 이름이 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
}
}
열거 형은 마치 실제 클래스가 아닙니다. 내부적으로 기본 유형과 동일하게 취급됩니다 (기본적으로 Int32). 따라서 하나의 열거 형에서 다른 열거 형으로 단일 값을 "복사"하고이를 정수로 캐스팅하여 동일한 지 비교하기 만하면됩니다.
열거 형은 다른 열거 형에서 파생 될 수 없지만 int, uint, short, ushort, long, ulong, byte 및 sbyte에서만 파생됩니다.
Pascal이 말했듯이 다른 열거 형 값이나 상수를 사용하여 열거 형 값을 초기화 할 수 있지만 그 정도입니다.
다른 가능한 해결책 :
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
@JaredPar가 이미 언급했듯이 불가능합니다. 이 문제를 해결하기 위해 논리를 넣으려는 것은 나쁜 습관입니다. 경우에 당신은이 base class
이 즉 enum
, 모든 수의 나열해야 enum-values
이, 그리고 클래스의 구현은 알고있는 값으로 작동합니다.
예 : 당신이 기본 클래스를 세웠 BaseCatalog
하고는있다 enum ProductFormats
( Digital
, Physical
). 그런 다음 당신은있을 수 있습니다 MusicCatalog
또는 BookCatalog
그 모두 포함 할 수 Digital
및 Physical
제품을, 그러나 클래스 인 경우 ClothingCatalog
,이있는 경우에만한다 Physical
제품.
나는 또한 Enum을 과부하시키고 싶었고이 페이지의 'Seven' 과 'Merlyn Morgan-Graham'의 대답을 중복 된 게시물 과 함께 몇 가지 개선 사항을 혼합하여 만들었습니다 .
다른 솔루션보다 내 솔루션의 주요 장점 :
- 기본 int 값의 자동 증분
- 자동 명명
이것은 즉시 사용 가능한 솔루션이며 프로젝트에 직접 삽입 될 수 있습니다. 그것은 내 요구에 맞게 설계되었으므로 일부를 좋아하지 않으면 자신의 코드로 바꾸십시오.
먼저 CEnum
모든 사용자 지정 열거 형에서 상속해야하는 기본 클래스 가 있습니다. .net Enum
유형 과 유사한 기본 기능이 있습니다 .
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;
}
}
}
둘째, 여기에는 2 개의 파생 Enum 클래스가 있습니다. 모든 파생 클래스는 예상대로 작동하려면 몇 가지 기본 방법이 필요합니다. 항상 같은 상용구 코드입니다. 아직 기본 클래스에 아웃소싱하는 방법을 찾지 못했습니다. 상속의 첫 번째 수준의 코드는 모든 후속 수준과 약간 다릅니다.
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
}
열거 형으로 상속을 수행 할 수 있지만 다음 유형으로 만 제한됩니다. int, uint, byte, sbyte, short, ushort, long, ulong
예 :
public enum Car:int{
Toyota,
Benz,
}
참고 URL : https://stackoverflow.com/questions/757684/enum-inheritance
'Programing' 카테고리의 다른 글
Ruby on Rails ActiveRecord 마이그레이션에서 너무 긴 색인 이름을 어떻게 처리합니까? (0) | 2020.02.28 |
---|---|
int에서 자릿수를 얻는 방법? (0) | 2020.02.28 |
"컨트롤에 코드 블록이 포함되어 있으므로 Controls 컬렉션을 수정할 수 없습니다" (0) | 2020.02.28 |
범위에서 CSS 고정 너비 (0) | 2020.02.28 |
Visual Studio Code에서 편집기와 통합 터미널 간 포커스 전환 (0) | 2020.02.28 |