С# enum в интерфейсе/базовом классе?
У меня проблема с перечислением
Мне нужно сделать перечисление в базовом классе или интерфейсе (но пустом)
class Base
{
public enum Test;
// ???
}
и после того, как в некоторых родительских классах будут выпущены разные экземпляры
class Parent1
{
public enum Test {A, B, C};
}
class Parent2
{
public enum Test {J, H, K};
}
и теперь у меня есть следующий класс с методом, когда я должен использовать enum
class Test<T>
{
public void Foo(Test enum)
{
int value = (int) enum;
// ...
}
}
Есть ли способ сделать что-то подобное?
Если мне не нужно использовать статические ints в каждом классе...
class Parent1
{
public static int A = 0;
public static int B = 5;
public static int C = 7;
}
class Parent2
{
public static int J = 1;
public static int H = 3;
public static int K = 6;
}
class Test<T>
{
public void Foo(int enum)
{
int value = enum;
// ...
}
}
Я выгляжу плохо в коде... в некоторых классах я должен использовать ~ 20 + переменные
Ответы
Ответ 1
Нет такой вещи, как абстрактное перечисление (которое может иметь разные реализации в подклассах), но может быть вариант:
class Base<T> where T : struct {
private T value;
public void Foo(T value) {
this.value = value;
}
}
class Parent1 : Base<Parent1.Enum1> {
public enum Enum1 {A, B, C};
}
class Parent2 : Base<Parent2.Enum2> {
public enum Enum2 { J, H, K };
}
Единственная проблема заключается в том, что это не гарантирует, что могут использоваться только перечисления - вы можете сделать это во время выполнения, хотя, например, в инициализаторе типа:
static Base() {
if (!typeof(T).IsEnum) throw new InvalidOperationException(
typeof(T).Name + " is not an enum");
}
Ответ 2
Удивительно, как часто я нахожу, что люди спорят о том, почему что-то требуется, вместо того, чтобы отвечать на заданный вопрос или держать schtum - любой из них был бы более полезен, чем тратить время на допрос, почему данный запрос был сделан в предпочтении другого запрос ответчик действительно знает ответ. Ответы на вопросы, которые не были заданы, никоим образом не помогают, хорошо, ребята?!
Возвращаясь к обсуждаемой теме, сегодня утром я выбрал именно этот сценарий и могу понять, почему было бы полезно определить Enum в интерфейсе или базовом классе, а затем переопределить тот же самый называемый Enum в классе, который происходит из базы или интерфейса. Одно использование для такой конструкции - объектно-реляционное сопоставление и привязка управления. У вас может быть набор Enums, которые описывают, какие свойства ваших производных классов могут быть привязаны к тем типам управления, как:
public enum WebControlTextBoxProperties { }
public enum WebControlLabelProperties { }
... и т.д.
Так как вы точно не знаете, какие свойства будут существовать для данного производного класса до тех пор, пока уместное наследование не вступит в силу, но поскольку вы также можете иметь последовательные методы, которые потребляют перечисленные выше перечисления в вашей базе или интерфейсе, это совершенно -valid, чтобы ожидать, что сможет определить, что Enum будет существовать в базе/интерфейсе, но точно определит, какие члены он имеет в определенном контексте в любых производных классах.
Я действительно хотел, чтобы это было возможно в С#, как в VB, потому что это была бы действительно полезная функция.
Ответ 3
Вы должны иметь возможность объявить перечисление в базовом классе, а затем изменить значения для производного класса i.e.
class MyClass
{
public enum TestEnum { }
public MyClass()
{
}
}
class MyDerivedClass
{
public enum TestEnum { value1, value2, value3 }
public MyDerivedClass()
{
}
}
Класс MyDervied будет иметь доступ к TestEnum.value1, TestEnum.value2, TestEnum.value3, где MyClass будет иметь доступ только к типу.
Однако лично я не вижу преимущества этого, я бы объявил ВСЕ значения enum в базовом классе и использовал только те, которые мне нужны для каждого класса.
Джеймс.
Ответ 4
Нет, это невозможно.
Обратите внимание, что многие перечисления часто указывают на проблему с дизайном (например, многие конструкции коммутаторов). Проверьте эту ссылку, чтобы увидеть пример того, как ее реорганизовать: Заменить условный полиморфизм.
Ответ 5
Нет, нет никакого способа обеспечить что-либо статичное в интерфейсе.
Возможно, вам нужно переосмыслить свой дизайн.
Ответ 6
Почему вы не можете определить перечисление в базовом классе:
class Base
{
public enum Test {A, B, C, J, H, K};
}
И используйте только соответствующие члены перечисления в производных классах?
Ответ 7
Я на работе, поэтому не могу полностью разобраться, но это возможно. Недостатком приведенного ниже кода является то, что вы не можете связать перечисления вместе, такие как TextBoxProperties и MyCustomTextBoxProperties: TextboxProperties
Вот код.
public enum Test
{
}
public enum ThisTest
{
MyVal1,
MyVal2,
MyVal3
}
public abstract class MyBase
{
public Test MyEnum { get; set; }
}
public class MyDerived : MyBase
{
public new ThisTest MyEnum { get; set; }
}
Ответ 8
ВЫ МОЖЕТЕ ИЗВЕСТИТЬ ЭНУМ!
Почему люди настаивают на том, чтобы претендовать на вещи невозможно без проверки чего-либо?
Конечно, документация .NET немного расплывчата по этому поводу, но класс System.Enum - это абстракция перечисления. Вы можете использовать System.Enum в качестве переменной, которая будет ТОЛЬКО принимать значения перечисления, и вы можете получить доступ к имени или значению типа перечисления через этот класс.
Например:
// abstracted enumeration value
Enum abstractEnum = null;
// set to the Console-Color enumeration value "Blue";
abstractEnum = System.ConsoleColor.Blue;
// the defined value of "ConsoleColor.Blue" is "9":
// you can get the value via the ToObject method:
Console.WriteLine((int)Enum.ToObject(abstractEnum.GetType(), abstractEnum));
// or via the GetHashCode() method:
Console.WriteLine(abstractEnum.GetHashCode());
// the name can also be acessed:
Console.WriteLine(Enum.GetName(abstractEnum.GetType(), abstractEnum));
Вывод из приведенного выше кода:
9
9
синий
Ответ 9
Мне нравится принятый ответ @Marc Gravell.
Поскольку я новичок stackoverflow, мне не разрешают комментировать. Но я хотел бы добавить, что полезно также проверить базовый тип перечисления - особенно если вы используете атрибут Flag и префикс побитового флага - Тестирование операций...
if ( !typeof(T).IsEnum || typeof(int) != Enum.GetUnderlyingType(typeof(T)) )
{
throw new InvalidOperationException( typeof(T).Name + " is not an enum");
}
Ответ 10
Вот решение, которое работает для меня:
в родительском классе, объявите поле как int, а не как enum:
protected int state;
поэтому родительский класс все еще может использовать это значение как int, чтобы обеспечить сериализацию и десериализацию этого значения на диск.
Затем, который переопределяет класс, можно сделать следующее:
enum states{
state1, state2
}
this.state = state1.toInt();
и может получить доступ к фактическому значению следующим образом:
...
if (this.state == states.state1.toInt()){
...
}
else{
...
}
где toInt() определяется в статическом классе следующим образом:
public static class Utils
{
public static int toInt(this state s)
{
return (int)s;
}
}