接口/基类中的C#枚举?

时间:2022-09-02 09:29:29

i have problem with enum

我有枚举的问题

I need make a enum in base class or interface (but empty one)

我需要在基类或接口中创建一个枚举(但是空的)

class Base 
{
   public enum Test;
   // ???
}

and after make diffrent enums in some parent classes

并在一些父类中创建不同的枚举之后

class Parent1
{
   public enum Test {A, B, C};
}

class Parent2
{
   public enum Test {J, H, K};
}

and now i have next class with method when i have to use enum

现在,当我必须使用枚举时,我有下一节课的方法

class Test<T>
{
   public void Foo(Test enum)
   {
      int value = (int) enum;
      // ...
   }
}

It's there any way to do something like that ?

有没有办法做那样的事情?

If not i have to use static ints in every class ...

如果不是,我必须在每个班级使用静态内联...

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;
      // ...
   }
}

I't looks bad in code ... in some classes i have to use ~20+ variables

我在代码中看起来不好......在某些类中我必须使用~20 +变量

10 个解决方案

#1


There is no such thing as an abstract enum (that can have different implementations in subclasses) - but generics may be an option:

没有抽象枚举(在子类中可以有不同的实现) - 但泛型可能是一个选项:

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 };
}

The only problem is that this doesn't enforce that only enums are usable - you can do this at runtime, though - for example in a type initializer:

唯一的问题是,这并不强制只有枚举可用 - 你可以在运行时执行此操作 - 例如在类型初始值设定项中:

static Base() {
    if (!typeof(T).IsEnum) throw new InvalidOperationException(
         typeof(T).Name + " is not an enum");
}

#2


It's amazing how often I find people arguing about why something is required, rather than answering the question asked or keeping schtum - either of which would be more helpful than wasting time questioning why a given enquiry has been made in preference to a different enquiry the respondent actually knows the answer to. Answering questions that have not been asked is in no way helpful, OK guys?!

令人惊讶的是,我经常发现人们争论为什么需要某些东西,而不是回答所提出的问题或保持问题 - 其中任何一个都比浪费时间质疑为什么特定的调查优先于受访者的不同调查更有帮助。实际上知道答案。回答没有被问过的问题绝对没有帮助,伙计们好吗?!

Getting back to the topic at hand, I've hit exactly the above scenario this morning, and can understand why it would be useful to be able to define an Enum in an interface or base class, then re-define that same-named Enum in a class that derives from either the base or interface. One use for such a design is in object-relational mapping and control binding. You might have a set of Enums that describe which Properties of your derived classes are bindable to which types of Control, such as:

回到手头的主题,我今天早上完全按照上面的场景,并且能够理解为什么能够在接口或基类中定义Enum,然后重新定义同名的Enum是有用的。在从基类或接口派生的类中。这种设计的一个用途是对象关系映射和控制绑定。您可能有一组枚举,用于描述派生类的哪些属性可绑定到哪些类型的Control,例如:

    public enum WebControlTextBoxProperties { }

    public enum WebControlLabelProperties { }

...and so on.

...等等。

Since you don't know exactly which Properties will exist for a given derived class until the pertinent inheritance takes effect, but since you may also wish to have consistent Methods that consume the above Enums in your base or interface, it's a perfectly-valid design to expect to be able to define that the Enum will exist in the base/interface, but define exactly what members it has in a specific context in any derived classes.

由于在相关继承生效之前您不确切知道给定派生类将存在哪些属性,但由于您可能还希望在基础或接口中使用一致的方法来使用上述枚举,因此它是完全有效的设计期望能够定义Enum将存在于基础/接口中,但确切地定义它在任何派生类中的特定上下文中具有哪些成员。

I really wish this were possible in C# as it is in VB, because it'd be a really useful feature.

我真的希望这在C#中是可行的,因为它在VB中,因为它是一个非常有用的功能。

#3


You should be able to declare an enum in a base class and then change the values per derived class i.e.

您应该能够在基类中声明枚举,然后更改每个派生类的值,即

class MyClass
{
    public enum TestEnum { }

    public MyClass()
    {
    }
}

class MyDerivedClass
{
    public enum TestEnum { value1, value2, value3 }

    public MyDerivedClass()
    {
    }
}

MyDervied class would have access to TestEnum.value1, TestEnum.value2, TestEnum.value3, where as MyClass would only have access to the type.

MyDervied类可以访问TestEnum.value1,TestEnum.value2,TestEnum.value3,其中MyClass只能访问该类型。

However, personally I don't see the advantage of doing this I would declare ALL the values of the enum in the base class and only use the ones I need per class.

但是,就我个人而言,我没有看到这样做的优点我会在基类中声明枚举的所有值,并且只使用每个类我需要的值。

James.

#4


No, it can't be done.

不,它无法完成。

Note that many enums often indicate a problem with design (many switch constructs, for example). Check this link to see an example of how to refactor this: Replace conditional with polymorphism.

请注意,许多枚举通常表明设计存在问题(例如,许多开关构造)。检查此链接以查看如何重构此示例:使用多态替换条件。

#5


No, there is no way to enforce anything static in an interface.

不,没有办法在界面中强制执行任何静态操作。

Perhaps you need to rethink your design.

也许你需要重新思考你的设计。

#6


Why cant you define the enum in base class:

为什么你不能在基类中定义枚举:

class Base 
{
   public enum Test {A, B, C, J, H, K};
}

And use only the relevant members of enum in derived classes?

并且在派生类中只使用枚举的相关成员?

#7


I am at work so cannot elaborate fully, but this is possible to a point. The downside to the code below is you cannot chain enums together, such as TextBoxProperties, and MyCustomTextBoxProperties : TextboxProperties

我在工作,所以不能完全阐述,但这是可能的。以下代码的缺点是您无法将枚举链接在一起,例如TextBoxProperties和MyCustomTextBoxProperties:TextboxProperties

Here is the code.

这是代码。

    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


YOU CAN ABSTRACT AN ENUM!

你可以抽象出一个枚举!

Why do people insist on claiming things are impossible without checking anything?

为什么人们坚持要求在没有检查的情况下做出事情是不可能的?

Sure, the .NET documentation is a little vague on this, but the System.Enum class, IS the abstraction of an enum. You can use System.Enum as a variable that will ONLY accept enumeration values, and you can access the name or value-type value of the enumeration through this class.

当然,.NET文档对此有点模糊,但System.Enum类是枚举的抽象。您可以将System.Enum用作仅接受枚举值的变量,并且可以通过此类访问枚举的名称或值类型值。

For example:

        // 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));

The output from the above code:

上面代码的输出:

9

9

Blue

#9


I like the accepted answer of @Marc Gravell. As i am a *-newbie i am not allowed to comment. But i would like to add, that it is useful to also check the underlying Type of the enum - especially if you use the Flag Attribute and preform bit-wise flag-Testing operations...

我喜欢@Marc Gravell的接受答案。由于我是*-newbie,我不允许发表评论。但我想补充一点,检查枚举的基础类型是有用的 - 特别是如果你使用Flag属性并执行逐位标记测试操作......

if ( !typeof(T).IsEnum || typeof(int) != Enum.GetUnderlyingType(typeof(T)) )
{
     throw new InvalidOperationException( typeof(T).Name + " is not an enum");
}

#10


Here's a solution that works for me:

这是一个适合我的解决方案:

in the parent class, declare the field as int, not as enum:

在父类中,将字段声明为int,而不是枚举:

protected int state;

so the parent class can still use this value as an int, in order to provide serialization and deserializion of this value to disk.

所以父类仍然可以将此值用作int,以便为磁盘提供此值的序列化和反序列化。

Then, who overrides the class can do this:

然后,谁覆盖该类可以这样做:

enum states{
  state1, state2
}

this.state = state1.toInt();

and can access the actual value like this:

并可以像这样访问实际值:

...
if (this.state == states.state1.toInt()){
      ...
}
else{
     ...
}

where toInt() is defined in a static class as follows:

其中toInt()在静态类中定义如下:

public static class Utils
{

    public static int toInt(this state s)
    {
        return (int)s;
    }
 }

#1


There is no such thing as an abstract enum (that can have different implementations in subclasses) - but generics may be an option:

没有抽象枚举(在子类中可以有不同的实现) - 但泛型可能是一个选项:

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 };
}

The only problem is that this doesn't enforce that only enums are usable - you can do this at runtime, though - for example in a type initializer:

唯一的问题是,这并不强制只有枚举可用 - 你可以在运行时执行此操作 - 例如在类型初始值设定项中:

static Base() {
    if (!typeof(T).IsEnum) throw new InvalidOperationException(
         typeof(T).Name + " is not an enum");
}

#2


It's amazing how often I find people arguing about why something is required, rather than answering the question asked or keeping schtum - either of which would be more helpful than wasting time questioning why a given enquiry has been made in preference to a different enquiry the respondent actually knows the answer to. Answering questions that have not been asked is in no way helpful, OK guys?!

令人惊讶的是,我经常发现人们争论为什么需要某些东西,而不是回答所提出的问题或保持问题 - 其中任何一个都比浪费时间质疑为什么特定的调查优先于受访者的不同调查更有帮助。实际上知道答案。回答没有被问过的问题绝对没有帮助,伙计们好吗?!

Getting back to the topic at hand, I've hit exactly the above scenario this morning, and can understand why it would be useful to be able to define an Enum in an interface or base class, then re-define that same-named Enum in a class that derives from either the base or interface. One use for such a design is in object-relational mapping and control binding. You might have a set of Enums that describe which Properties of your derived classes are bindable to which types of Control, such as:

回到手头的主题,我今天早上完全按照上面的场景,并且能够理解为什么能够在接口或基类中定义Enum,然后重新定义同名的Enum是有用的。在从基类或接口派生的类中。这种设计的一个用途是对象关系映射和控制绑定。您可能有一组枚举,用于描述派生类的哪些属性可绑定到哪些类型的Control,例如:

    public enum WebControlTextBoxProperties { }

    public enum WebControlLabelProperties { }

...and so on.

...等等。

Since you don't know exactly which Properties will exist for a given derived class until the pertinent inheritance takes effect, but since you may also wish to have consistent Methods that consume the above Enums in your base or interface, it's a perfectly-valid design to expect to be able to define that the Enum will exist in the base/interface, but define exactly what members it has in a specific context in any derived classes.

由于在相关继承生效之前您不确切知道给定派生类将存在哪些属性,但由于您可能还希望在基础或接口中使用一致的方法来使用上述枚举,因此它是完全有效的设计期望能够定义Enum将存在于基础/接口中,但确切地定义它在任何派生类中的特定上下文中具有哪些成员。

I really wish this were possible in C# as it is in VB, because it'd be a really useful feature.

我真的希望这在C#中是可行的,因为它在VB中,因为它是一个非常有用的功能。

#3


You should be able to declare an enum in a base class and then change the values per derived class i.e.

您应该能够在基类中声明枚举,然后更改每个派生类的值,即

class MyClass
{
    public enum TestEnum { }

    public MyClass()
    {
    }
}

class MyDerivedClass
{
    public enum TestEnum { value1, value2, value3 }

    public MyDerivedClass()
    {
    }
}

MyDervied class would have access to TestEnum.value1, TestEnum.value2, TestEnum.value3, where as MyClass would only have access to the type.

MyDervied类可以访问TestEnum.value1,TestEnum.value2,TestEnum.value3,其中MyClass只能访问该类型。

However, personally I don't see the advantage of doing this I would declare ALL the values of the enum in the base class and only use the ones I need per class.

但是,就我个人而言,我没有看到这样做的优点我会在基类中声明枚举的所有值,并且只使用每个类我需要的值。

James.

#4


No, it can't be done.

不,它无法完成。

Note that many enums often indicate a problem with design (many switch constructs, for example). Check this link to see an example of how to refactor this: Replace conditional with polymorphism.

请注意,许多枚举通常表明设计存在问题(例如,许多开关构造)。检查此链接以查看如何重构此示例:使用多态替换条件。

#5


No, there is no way to enforce anything static in an interface.

不,没有办法在界面中强制执行任何静态操作。

Perhaps you need to rethink your design.

也许你需要重新思考你的设计。

#6


Why cant you define the enum in base class:

为什么你不能在基类中定义枚举:

class Base 
{
   public enum Test {A, B, C, J, H, K};
}

And use only the relevant members of enum in derived classes?

并且在派生类中只使用枚举的相关成员?

#7


I am at work so cannot elaborate fully, but this is possible to a point. The downside to the code below is you cannot chain enums together, such as TextBoxProperties, and MyCustomTextBoxProperties : TextboxProperties

我在工作,所以不能完全阐述,但这是可能的。以下代码的缺点是您无法将枚举链接在一起,例如TextBoxProperties和MyCustomTextBoxProperties:TextboxProperties

Here is the code.

这是代码。

    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


YOU CAN ABSTRACT AN ENUM!

你可以抽象出一个枚举!

Why do people insist on claiming things are impossible without checking anything?

为什么人们坚持要求在没有检查的情况下做出事情是不可能的?

Sure, the .NET documentation is a little vague on this, but the System.Enum class, IS the abstraction of an enum. You can use System.Enum as a variable that will ONLY accept enumeration values, and you can access the name or value-type value of the enumeration through this class.

当然,.NET文档对此有点模糊,但System.Enum类是枚举的抽象。您可以将System.Enum用作仅接受枚举值的变量,并且可以通过此类访问枚举的名称或值类型值。

For example:

        // 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));

The output from the above code:

上面代码的输出:

9

9

Blue

#9


I like the accepted answer of @Marc Gravell. As i am a *-newbie i am not allowed to comment. But i would like to add, that it is useful to also check the underlying Type of the enum - especially if you use the Flag Attribute and preform bit-wise flag-Testing operations...

我喜欢@Marc Gravell的接受答案。由于我是*-newbie,我不允许发表评论。但我想补充一点,检查枚举的基础类型是有用的 - 特别是如果你使用Flag属性并执行逐位标记测试操作......

if ( !typeof(T).IsEnum || typeof(int) != Enum.GetUnderlyingType(typeof(T)) )
{
     throw new InvalidOperationException( typeof(T).Name + " is not an enum");
}

#10


Here's a solution that works for me:

这是一个适合我的解决方案:

in the parent class, declare the field as int, not as enum:

在父类中,将字段声明为int,而不是枚举:

protected int state;

so the parent class can still use this value as an int, in order to provide serialization and deserializion of this value to disk.

所以父类仍然可以将此值用作int,以便为磁盘提供此值的序列化和反序列化。

Then, who overrides the class can do this:

然后,谁覆盖该类可以这样做:

enum states{
  state1, state2
}

this.state = state1.toInt();

and can access the actual value like this:

并可以像这样访问实际值:

...
if (this.state == states.state1.toInt()){
      ...
}
else{
     ...
}

where toInt() is defined in a static class as follows:

其中toInt()在静态类中定义如下:

public static class Utils
{

    public static int toInt(this state s)
    {
        return (int)s;
    }
 }