我在一个低级名称空间中有一个枚举。我想在中层名称空间中提供一个“继承”低层枚举的类或枚举。
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
我希望这是可能的,或者可能有某种类可以取代枚举消费,这将为枚举提供一个抽象层,但仍然让该类的实例访问枚举。
想法吗?
编辑:
我没有在类中将其转换为const的原因之一是我必须使用的服务需要低级枚举。我已经获得了wsdl和xsd,它们将结构定义为枚举。该服务不可更改。
这样做的方法(如果有必要的话)是实现自己的类结构,其中包括您希望从继承枚举的概念中获得的特性,而且您还可以添加更多特性。
您只需实现相等比较器和函数来查找您自己编写的值。
您可以将构造函数设为私有,并声明类和任何子类的静态实例。
或者为您的问题找到一个简单的解决方法,并坚持使用本机枚举实现。
继承枚举的重代码实现:
/// <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,尽管子类需要一个单独的枚举。
枚举类本身可以用各种标志、消息、函数等来装饰。
泛型实现将减少大量代码。
简短的回答是否定的。如果你想,你可以玩一点:
你可以这样做:
private enum Base
{
A,
B,
C
}
private enum Consume
{
A = Base.A,
B = Base.B,
C = Base.C,
D,
E
}
但是,它并没有那么好,因为Base。A !=消费。一个
不过,你总是可以这样做:
public static class Extensions
{
public static T As<T>(this Consume c) where T : struct
{
return (T)System.Enum.Parse(typeof(T), c.ToString(), false);
}
}
为了在基础和消费之间交叉…
你也可以将枚举的值转换为整数,并将它们比较为整数而不是enum,但这也很糟糕。
扩展方法return应该将其类型转换为T类型。
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
}
}
我知道我来这个派对有点晚了,但这是我的意见。
我们都很清楚,框架不支持Enum继承。在这篇文章中提出了一些非常有趣的解决办法,但没有一个是我想要的,所以我自己尝试了一下。
介绍:ObjectEnum
您可以在这里查看代码和文档:https://github.com/dimi3tron/ObjectEnum。
软件包在这里:https://www.nuget.org/packages/ObjectEnum
或者直接安装它:install - package ObjectEnum
简而言之,ObjectEnum<TEnum>充当任何enum的包装器。通过重写子类中的GetDefinedValues(),可以指定哪些enum值对这个特定的类有效。
添加了许多操作符重载,以使ObjectEnum<TEnum>实例的行为就像底层枚举的实例一样,记住已定义的值限制。这意味着您可以轻松地将实例与int或enum值进行比较,从而在开关情况或任何其他条件中使用它。
我想参考上面提到的github回购的例子和进一步的信息。
我希望这对你有用。请随意评论或在github上打开一个问题以获得进一步的想法或评论。
下面是几个简短的例子,说明你可以用ObjectEnum<TEnum>做什么:
var sunday = new WorkDay(DayOfWeek.Sunday); //throws exception
var monday = new WorkDay(DayOfWeek.Monday); //works fine
var label = $"{monday} is day {(int)monday}." //produces: "Monday is day 1."
var mondayIsAlwaysMonday = monday == DayOfWeek.Monday; //true, sorry...
var friday = new WorkDay(DayOfWeek.Friday);
switch((DayOfWeek)friday){
case DayOfWeek.Monday:
//do something monday related
break;
/*...*/
case DayOfWeek.Friday:
//do something friday related
break;
}
你可以通过类实现你想要的:
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;