Подтвердить что ты не робот

С# 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 + переменные

4b9b3361

Ответ 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;
    }
 }