Asked  7 Months ago    Answers:  5   Viewed   22 times

I have an enum in a low level namespace. I'd like to provide a class or enum in a mid level namespace that "inherits" the low level enum.

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

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

I'm hoping that this is possible, or perhaps some kind of class that can take the place of the enum consume which will provide a layer of abstraction for the enum, but still let an instance of that class access the enum.

Thoughts?

EDIT: One of the reasons I haven't just switched this to consts in classes is that the low level enum is needed by a service that I must consume. I have been given the WSDLs and the XSDs, which define the structure as an enum. The service cannot be changed.

 Answers

26

This is not possible. Enums cannot inherit from other enums. In fact all enums must actually inherit from System.Enum. C# allows syntax to change the underlying representation of the enum values which looks like inheritance, but in actuality they still inherit from System.enum.

See section 8.5.2 of the CLI spec for the full details. Relevant information from the spec

  • All enums must derive from System.Enum
  • Because of the above, all enums are value types and hence sealed
Tuesday, June 1, 2021
 
Pradip
answered 7 Months ago
38

To add to @StackedCrooked answer, you can overload operator++, operator-- and operator* and have iterator like functionality.

enum Color {
    Color_Begin,
    Color_Red = Color_Begin,
    Color_Orange,
    Color_Yellow,
    Color_Green,
    Color_Blue,
    Color_Indigo,
    Color_Violet,
    Color_End
};

namespace std {
template<>
struct iterator_traits<Color>  {
  typedef Color  value_type;
  typedef int    difference_type;
  typedef Color *pointer;
  typedef Color &reference;
  typedef std::bidirectional_iterator_tag
    iterator_category;
};
}

Color &operator++(Color &c) {
  assert(c != Color_End);
  c = static_cast<Color>(c + 1);
  return c;
}

Color operator++(Color &c, int) {
  assert(c != Color_End); 
  ++c;
  return static_cast<Color>(c - 1);
}

Color &operator--(Color &c) {
  assert(c != Color_Begin);
  return c = static_cast<Color>(c - 1);
}

Color operator--(Color &c, int) {
  assert(c != Color_Begin); 
  --c;
  return static_cast<Color>(c + 1);
}

Color operator*(Color c) {
  assert(c != Color_End);
  return c;
}

Let's test with some <algorithm> template

void print(Color c) {
  std::cout << c << std::endl;
}

int main() {
  std::for_each(Color_Begin, Color_End, &print);
}

Now, Color is a constant bidirectional iterator. Here is a reusable class i coded while doing it manually above. I noticed it could work for many more enums, so repeating the same code all over again is quite tedious

// Code for testing enum_iterator
// --------------------------------

namespace color_test {
enum Color {
  Color_Begin,
  Color_Red = Color_Begin,
  Color_Orange,
  Color_Yellow,
  Color_Green,
  Color_Blue,
  Color_Indigo,
  Color_Violet,
  Color_End
};

Color begin(enum_identity<Color>) {
  return Color_Begin;
}

Color end(enum_identity<Color>) {
  return Color_End;
}
}

void print(color_test::Color c) {
  std::cout << c << std::endl;
}

int main() {
  enum_iterator<color_test::Color> b = color_test::Color_Begin, e;
  while(b != e)
    print(*b++);
}

Implementation follows.

template<typename T>
struct enum_identity { 
  typedef T type; 
};

namespace details {
void begin();
void end();
}

template<typename Enum>
struct enum_iterator 
  : std::iterator<std::bidirectional_iterator_tag, 
                  Enum> {
  enum_iterator():c(end()) { }

  enum_iterator(Enum c):c(c) { 
    assert(c >= begin() && c <= end());
  }

  enum_iterator &operator=(Enum c) {
    assert(c >= begin() && c <= end());
    this->c = c; 
    return *this;
  }

  static Enum begin() {
    using details::begin; // re-enable ADL
    return begin(enum_identity<Enum>());
  }

  static Enum end() {
    using details::end; // re-enable ADL
    return end(enum_identity<Enum>());
  }

  enum_iterator &operator++() {
    assert(c != end() && "incrementing past end?");
    c = static_cast<Enum>(c + 1);
    return *this;
  }

  enum_iterator operator++(int) {
    assert(c != end() && "incrementing past end?");
    enum_iterator cpy(*this);
    ++*this;
    return cpy;
  }

  enum_iterator &operator--() {
    assert(c != begin() && "decrementing beyond begin?");
    c = static_cast<Enum>(c - 1);
    return *this;
  }

  enum_iterator operator--(int) {
    assert(c != begin() && "decrementing beyond begin?");
    enum_iterator cpy(*this);
    --*this;
    return cpy;
  }

  Enum operator*() {
    assert(c != end() && "cannot dereference end iterator");
    return c;
  }

  Enum get_enum() const {
    return c;
  }

private:
  Enum c;
};

template<typename Enum>
bool operator==(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
  return e1.get_enum() == e2.get_enum();
}

template<typename Enum>
bool operator!=(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
  return !(e1 == e2);
}
Thursday, June 3, 2021
 
aWebDeveloper
answered 6 Months ago
76

It has no special meaning, just the way the compiler works, it's mainly for this reason:

[FlagsAttribute]
public enum DependencyPropertyOptions : byte
{
           Default = 1,
           ReadOnly = 2,
           Optional = 4,
           DelegateProperty = 32,
           Metadata = 8,
           NonSerialized = 16,
           //EnumPropertyIWantToCommentOutEasily = 32
}

By comment request: This info comes straight out of the C# Specification (Page 355/Section 17.7)

Like Standard C++, C# allows a trailing comma at the end of an array-initializer. This syntax provides flexibility in adding or deleting members from such a list, and simplifies machine generation of such lists.

Wednesday, June 9, 2021
 
viper
answered 6 Months ago
61

Here is how I reason about it:

Only use inheritance if the role/type will never change. e.g.

using inheritance for things like:

Fireman <- Employee <- Person is wrong.

as soon as Freddy the fireman changes job or becomes unemployed, you have to kill him and recreate a new object of the new type with all of the old relations attached to it.

So the naive solution to the above problem would be to give a JobTitle enum property to the person class. This can be enough in some scenarios, e.g. if you don't need very complex behaviors associated with the role/type.

The more correct way would be to give the person class a list of roles. Each role represents e.g an employment with a time span.

e.g.

freddy.Roles.Add(new Employement( employmentDate, jobTitle ));

or if that is overkill:

freddy.CurrentEmployment = new Employement( employmentDate, jobTitle );

This way , Freddy can become a developer w/o we having to kill him first.

However, all my ramblings still haven't answered if you should use an enum or type hierarchy for the jobtitle.

In pure in mem OO I'd say that it's more correct to use inheritance for the jobtitles here.

But if you are doing O/R mapping you might end up with a bit overcomplex data model behind the scenes if the mapper tries to map each sub type to a new table. So in such cases, I often go for the enum approach if there is no real/complex behavior associated with the types. I can live with a "if type == JobTitles.Fireman ..." if the usage is limited and it makes things easer or less complex.

e.g. the Entity Framework 4 designer for .NET can only map each sub type to a new table. and you might get an ugly model or alot of joins when you query your database w/o any real benefit.

However I do use inheritance if the type/role is static. e.g. for Products.

you might have CD <- Product and Book <- Product. Inheritance wins here because in this case you most likely have different state associated with the types. CD might have a number of tracks property while a book might have number of pages property.

So in short, it depends ;-)

Also, at the end of the day you will most likely end up with a lot of switch statements either way. Let's say you want to edit a "Product" , even if you use inheritance, you will probably have code like this:

if (product is Book) Response.Redicted("~/EditBook.aspx?id" + product.id);

Because encoding the edit book url in the entity class would be plain ugly since it would force your business entites to know about your site structure etc.

Sunday, August 1, 2021
 
Pwner
answered 4 Months ago
99

A quick and dirty way using Linq:

IEnumerable<EnumDisplayNameAttribute> attributes = 
    Enum.GetValues(typeof(MyEnum))
        .Cast<MyEnum>()
        .Where(v => enumVar.HasFlag(v))
        .Select(v => typeof(MyEnum).GetField(v.ToString()))
        .Select(f => f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), false)[0])
        .Cast<EnumDisplayNameAttribute>();

Or in query syntax:

IEnumerable<EnumDisplayNameAttribute> attributes = 
    from MyEnum v in Enum.GetValues(typeof(MyEnum))
    where enumVar.HasFlag(v)
    let f = typeof(MyEnum).GetField(v.ToString())
    let a = f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), false)[0]
    select ((EnumDisplayNameAttribute)a);

Alternatively, if there could possibly be multiple attributes on each field, you'll probably want to do this:

IEnumerable<EnumDisplayNameAttribute> attributes = 
    Enum.GetValues(typeof(MyEnum))
        .Cast<MyEnum>()
        .Where(v => enumVar.HasFlag(v))
        .Select(v => typeof(MyEnum).GetField(v.ToString()))
        .SelectMany(f => f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), false))
        .Cast<EnumDisplayNameAttribute>();

Or in query syntax:

IEnumerable<EnumDisplayNameAttribute> attributes = 
    from MyEnum v in Enum.GetValues(typeof(MyEnum))
    where enumVar.HasFlag(v))
    let f = typeof(MyEnum).GetField(v.ToString())
    from EnumDisplayNameAttribute a in f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), false)
    select a;
Thursday, August 26, 2021
 
palAlaa
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share