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,它们将结构定义为枚举。该服务不可更改。


当前回答

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

其他回答

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

忽略base是保留字的事实,你不能继承enum。

你能做的最好的事情就是这样:

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

因为它们都是相同的基类型(即:int),你可以将一个类型的实例的值赋给另一个类型,这就是强制转换。虽然不理想,但很有效。

这样做的方法(如果有必要的话)是实现自己的类结构,其中包括您希望从继承枚举的概念中获得的特性,而且您还可以添加更多特性。 您只需实现相等比较器和函数来查找您自己编写的值。 您可以将构造函数设为私有,并声明类和任何子类的静态实例。 或者为您的问题找到一个简单的解决方法,并坚持使用本机枚举实现。

继承枚举的重代码实现:

/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceBase
{

    //members
    protected int _id;
    protected string _name;

    //constructors
    private ServiceBase(int id, string name)
    {
        _id = id;
        _name = name;
    }

    //onlu required if subclassing
    protected ServiceBase(int id, string name, bool isSubClass = true )
    {
        if( id <= _maxServiceId )
            throw new InvalidProgramException("Bad Id in ServiceBase" );
        _id = id;
        _name = name;
        
    }

    //members
    public int Id => _id;
    public string Name => _name;
    public virtual ServiceBase getService(int serviceBaseId)
    {
        return ALLBASESERVICES.SingleOrDefault(s => s.Id == _id);
    }
    
    //implement iComparable if required
    
    //static methods
    public static ServiceBase getServiceOrDefault(int serviceBaseId)
    {
        return SERVICE1.getService(serviceBaseId);
    }

    //Enumerations Here
    public static ServiceBase SERVICE1 = new ServiceBase( 1, "First Service" );
    public static ServiceBase SERVICE2 = new ServiceBase( 2, "Second Service" );

    protected static ServiceBase[] ALLBASESERVICES =
    {
        //Enumerations list
        SERVICE1,
        SERVICE2
    };
    private static int _maxServiceId = ALLBASESERVICES.Max( s => s.Id );

    //only required if subclassing
    protected static ServiceBase[] combineServices(ServiceBase[] array1, ServiceBase[] array2)
    {
        List<ServiceBase> serviceBases = new List<ServiceBase>();
        serviceBases.AddRange( array1 );
        serviceBases.AddRange( array2 );
        return serviceBases.ToArray();
    }

}

/// <summary>
/// Generic Design for implementing inheritable enum
/// </summary>
public class ServiceJobs : ServiceBase
{
    
    //constructor
    private ServiceJobs(int id, string name)
    : base( id, name )
    {
        _id = id;
        _name = name;
    }

    //only required if subclassing
    protected ServiceJobs(int id, string name, bool isSubClass = true )
    : base( id, name )
    {
        if( id <= _maxServiceId )
            throw new InvalidProgramException("Bad Id in ServiceJobs" );
        _id = id;
        _name = name;
        
    }

    //members
    public override ServiceBase getService(int serviceBaseId)
    {
        if (ALLSERVICES == null)
        {
            ALLSERVICES = combineServices(ALLBASESERVICES, ALLJOBSERVICES);
        }
        return ALLSERVICES.SingleOrDefault(s => s.Id == _id);
    }

    //static methods
    public static ServiceBase getServiceOrDefault(int serviceBaseId)
    {
        return SERVICE3.getService(serviceBaseId);
    }

    //sub class services here
    public static ServiceBase SERVICE3 = new ServiceJobs( 3, "Third Service" );
    public static ServiceBase SERVICE4 = new ServiceJobs( 4, "Forth Service" );
    private static int _maxServiceId = ALLJOBSERVICES.Max( s => s.Id );

    private static ServiceBase[] ALLJOBSERVICES =
    {
        //subclass service list
        SERVICE3,
        SERVICE4
    };

    //all services including superclass items
    private static ServiceBase[] ALLSERVICES = null;

}

注意,您可以使用枚举而不是int作为id,尽管子类需要一个单独的枚举。 枚举类本身可以用各种标志、消息、函数等来装饰。 泛型实现将减少大量代码。

我知道这个回答有点晚了,但这就是我最后做的:

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)
{
}

枚举并不是真正的类,即使它们看起来像类。在内部,它们被视为它们的基础类型(默认为Int32)。因此,您只能通过将单个值从一个枚举“复制”到另一个枚举,并将它们转换为整数来比较它们是否相等来做到这一点。