Вы можете использовать словари для этого. Словари - это хранилища ключей и ценностей.
>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2
Вы можете использовать имена переменных ключей для достижения эффекта переменных переменных без риска для безопасности.
>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'
В тех случаях, когда вы думаете сделать что-то вроде
var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...
список может быть более подходящим, чем dict. Список представляет упорядоченную последовательность объектов с целыми индексами:
l = ['foo', 'bar', 'baz']
print(l[1]) # prints bar, because indices start at 0
l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes']
Для упорядоченных последовательностей списки удобнее, чем dict с целыми ключами, потому что списки поддерживают итерацию в порядке индекса, slicing , append
и другие операции, которые потребуют неудобного управления ключами с помощью dict.
Это невозможно. Перечисления не могут наследоваться из других перечислений. Фактически все перечисления должны фактически наследоваться от System.Enum
. C # позволяет синтаксису изменять базовое представление значений enum, которое выглядит как наследование, но на самом деле они все еще наследуются от System.enum.
См. Раздел 8.5.2 спецификации CLI для получения полной информации. Соответствующая информация из спецификации
System.Enum
Короткий ответ - нет. Вы можете играть немного, если хотите:
Вы всегда можете сделать что-то вроде этого:
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);
}
}
Чтобы пересечь базу и потребление ...
Вы также может отличать значения перечислений как ints и сравнивать их как ints вместо enum, но этот тип отстой тоже.
Возврат метода расширения должен ввести cast type T.
Base.A == (Base)Consume.A
– Kresimir
29 August 2014 в 20:55
int
будет иметь больший смысл. Когда в перечислении будет дробная часть!?!?!
– ErikE
20 July 2015 в 21:18
Решения, вышеперечисленные с использованием классов с 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) { /* ... */ }
// ...
}
object
используется , как рекомендуется для lock
? Я не могу придумать хороший способ сделать эту идею совместимой с частью «нумерации» enum
, где MyEnum.First < MyEnum.Second
. Но если упорядочение не важно для вашего enum
, то это будет отличный способ избежать магических int-констант.
– binki
1 April 2014 в 18:05
object
, сделает значения разными для каждого экземпляра сборки, чтобы они не могли быть сериализованы.
– ivan_pozdeev
16 December 2014 в 10:20
Это невозможно (как уже упоминалось @JaredPar). Попытка заставить логику обойти это - плохая практика. Если у вас есть base class
, у которого есть enum
, вы должны указать список всех возможных enum-values
, а реализация класса должна работать со значениями, которые он знает.
Например. Предположим, что у вас есть базовый класс BaseCatalog
, и он имеет enum ProductFormats
(Digital
, Physical
). Затем вы можете иметь MusicCatalog
или BookCatalog
, которые могут содержать файлы Digital
и Physical
. Но если класс ClothingCatalog
, он должен содержать только продукты Physical
.
Перечисления не могут быть перегружены из других перечислений, но только из int, uint, short, ushort, long, ulong, byte и sbyte.
Как и Паскаль, вы можете использовать другие значения или константы enum для инициализации значения перечисления, но это все.
Перечисления не являются фактическими классами, даже если они выглядят так. Внутри они обрабатываются так же, как и их базовый тип (по умолчанию Int32). Поэтому вы можете сделать это только путем «копирования» одиночных значений из одного перечня в другой и отведения их к их целочисленному числу, чтобы сравнить их для равенства.
Вы можете достичь того, чего хотите с помощью классов:
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;
Enum.GetValues(typeof(MyEnum)
– Mike de Klerk
3 June 2015 в 07:46
void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
– mnieto
5 June 2015 в 10:08
Игнорируя тот факт, что база является зарезервированным словом, вы не можете выполнять наследование перечисления.
Лучшее, что вы могли бы сделать, это что-то вроде этого:
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());
}
}
re все тот же базовый тип (т. е. int) вы можете назначить значение из экземпляра одного типа другому, отличному от другого. Не идеально, но он работает.
другое возможное решение:
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
Вы можете выполнять наследование в перечислении, однако оно ограничено только следующими типами. int, uint, byte, sbyte, short, ushort, long, ulong
Например,
public enum Car:int{
Toyota,
Benz,
}
Я также хотел перегрузить Enums и создал смесь ответа «Семь» на этой странице и на ответ «Мерлин Морган-Грэм» на дубликат сообщения этого , плюс несколько улучшений. Основные преимущества моего решения по сравнению с другими:
является готовым решением и может быть непосредственно вставлено в ваш проект. Это связано с моими потребностями, поэтому, если вам не нравятся некоторые его части, просто замените их собственным кодом.
Во-первых, есть базовый класс 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
}
Это то, что я сделал. То, что я сделал по-другому, использует одно и то же имя и ключевое слово new
для «потребления» enum
. Поскольку имя enum
одинаково, вы можете просто бездумно использовать его, и это будет правильно. Плюс вы получаете intellisense. Вам просто нужно вручную позаботиться, настроив его, чтобы значения скопировались из базы и синхронизировали их. Вы можете помочь в этом вместе с комментариями кодов. Это еще одна причина, по которой в базе данных при сохранении значений 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
}
}
SmallMedium = 100,
), чтобы вы могли поддерживать совместимость со старыми версиями своего программного обеспечения при добавлении новых значений в базовый класс. Например, добавление размера Huge
в вашем базовом enum присваивает 4
его значение, но 4
уже используется SmallMedium
в производном классе.
– Roberto
2 April 2017 в 10:49
Huge
в базовый класс потребует Huge
в подклассе перед SmallMedium
– toddmo
2 April 2017 в 21:36
BaseBall
не может быть самым умным именем здесь. Это сбивает с толку. Так как бейсбол на самом деле вещь. Если вы пропустите, что это всего лишь базовый класс для мяча, выглядит странно, что волейбол наследуется от физически меньшего бейсбола :). Мое предложение - просто использовать Ball
– Nick N.
12 March 2018 в 11:25
Я знаю, что этот ответ довольно поздний, но это то, что я закончил:
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)
{
}