2023-09-27 07:00:01

Enum“继承”

我在一个低级名称空间中有一个枚举。我想在中层名称空间中提供一个“继承”低层枚举的类或枚举。

namespace low
{
   public enum base
   {
      x, y, z
   }
}

namespace mid
{
   public enum consume : low.base
   {
   }
}

我希望这是可能的,或者可能有某种类可以取代枚举消费,这将为枚举提供一个抽象层,但仍然让该类的实例访问枚举。

想法吗?

编辑: 我没有在类中将其转换为const的原因之一是我必须使用的服务需要低级枚举。我已经获得了wsdl和xsd,它们将结构定义为枚举。该服务不可更改。


当前回答

你可以通过类实现你想要的:

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;

其他回答

This is what I did. What I've done differently is use the same name and the new keyword on the "consuming" enum. Since the name of the enum is the same, you can just mindlessly use it and it will be right. Plus you get intellisense. You just have to manually take care when setting it up that the values are copied over from the base and keep them sync'ed. You can help that along with code comments. This is another reason why in the database when storing enum values I always store the string, not the value. Because if you are using automatically assigned increasing integer values those can change over time.

// Base Class for balls 
public class Ball
{
    // keep synced with subclasses!
    public enum Sizes
    {
        Small,
        Medium,
        Large
    }
}

public class VolleyBall : Ball
{
    // keep synced with base class!
    public new enum Sizes
    {
        Small  = Ball.Sizes.Small,
        Medium = Ball.Sizes.Medium,
        Large  = Ball.Sizes.Large,
        SmallMedium,
        MediumLarge,
        Ginormous
    }
}

可选择的解决方案

在我的公司,我们避免“跳过项目”而进入不常见的低级别项目。例如,我们的表示层/API层只能引用域层,而域层只能引用数据层。

但是,当表示层和域层都需要引用枚举时,这就出现了问题。

下面是我们已经实现的解决方案(到目前为止)。这是一个很好的解决方案,对我们很有效。其他答案都围绕着这个问题。

基本的前提是枚举不能被继承——但是类可以。所以…

// In the lower level project (or DLL)...
public abstract class BaseEnums
{
    public enum ImportanceType
    {
        None = 0,
        Success = 1,
        Warning = 2,
        Information = 3,
        Exclamation = 4
    }

    [Flags]
    public enum StatusType : Int32
    {
        None = 0,
        Pending = 1,
        Approved = 2,
        Canceled = 4,
        Accepted = (8 | Approved),
        Rejected = 16,
        Shipped = (32 | Accepted),
        Reconciled = (64 | Shipped)
    }

    public enum Conveyance
    {
        None = 0,
        Feet = 1,
        Automobile = 2,
        Bicycle = 3,
        Motorcycle = 4,
        TukTuk = 5,
        Horse = 6,
        Yak = 7,
        Segue = 8
    }

然后,在另一个更高级别的项目中“继承”枚举…

// Class in another project
public sealed class SubEnums: BaseEnums
{
   private SubEnums()
   {}
}

这有三个真正的优势……

两个项目中的枚举定义自动相同- by 定义。 对枚举定义的任何更改都是自动的 在不需要做任何修改的情况下 第二个类。 枚举基于相同的代码-因此值可以很容易地进行比较(有一些注意事项)。

要在第一个项目中引用枚举,您可以使用类的前缀:baseenumes . statustype . pending或在usings中添加“using static BaseEnums;”语句。

然而,在第二个项目中,当处理继承的类时,我无法获得“使用静态…”的方法,因此所有对“继承的枚举”的引用都将以类为前缀,例如subenumes . statustype . pending。如果有人提出了允许在第二个项目中使用“使用静态”方法的方法,请告诉我。

我相信这是可以调整的,使它变得更好——但这实际上是有效的,我已经在工作项目中使用了这种方法。

这是不可能的。枚举不能从其他枚举继承。事实上,所有枚举都必须从System.Enum继承。c#允许语法改变枚举值的底层表示,这看起来像继承,但实际上它们仍然继承自System.enum。

详细信息请参见CLI规范的8.5.2节。来自规范的相关信息

所有枚举必须从System派生。枚举 因此,所有枚举都是值类型,因此是密封的

您可以在enum中执行继承,但它仅限于以下类型。 Int, uint, byte, sbyte, short, ushort, long, ulong

E.g.

public enum Car:int{
Toyota,
Benz,
}

上述使用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) { /* ... */ }
    // ...
}