13,456,800 members
alternative version

#### Stats

53.3K views
14 bookmarked
Posted 2 Apr 2008

# Tree Structured Enumerations

, 2 Apr 2008
The way to maintain a tree structured enumeration while having all the advantages of the standard ones

## Introduction

In this article, I want to show you an approach of how a structured enumeration can be handled by C#.

## Background

While playing with my little home project, I stumbled upon a problem of having all those category enumerations displayed in a tree. I wanted to keep it simple - as the enumerations are - while avoiding the need to create structured object hierarchies for every one of them. So, after a bit of thinking, I came up with this solution. I hope you'll find it useful or at least interesting.

## Structured Enumeration

First, we have to tickle our old plain list enumeration a bit and convert it to a structured one. I chose the animal categories.. well.. to confess, I'm always having slight difficulties to find a good example, but here it is anyway.

```[Structured(100)]
public enum AnimalKind
{
Unknown         = 00000,

DomesticAnimals = 00001,
Dog           = 00100,
Dalmatin    = 10000,
Greyhound   = 10001,
Malamute    = 10002,
Terrier     = 10003,
Cat           = 00101,

WildAnimals     = 00002,
Ape           = 00200,
Chimpanzee  = 20000,
Gorrila     = 20001,
Orangutan   = 20002,
Deer          = 00201
}```

As you might notice, some unknown `attribute `is used there. Let me introduce it to you.

```[AttributeUsage(AttributeTargets.Enum)]
public class StructuredAttribute : Attribute
{
public int span;

public int Span
{
get { return span; }
set { span = value; }
}

public StructuredAttribute(int span)
{
this.span = span;
}
}```

This simple `attribute `is composed of only one property (an automatic property may be used in C# 3.0, God I love those). The `attribute `is responsible for determining the span (multiplicator) of the tree levels thus allowing us to distinguish the hierarchy later.

Well.. later is now because this ought to be a short article. I took the liberty to create the utility class to help us deal with the structured enumerations. It consists of two `static `methods. Let's take a closer look at them.

## Methods

The `IsChild `method is used to determine if one enumeration value is placed under another one. I guess the utility can be easily extended by a method determining the whole chain of the parents from a particular `enum `value.

```public static bool IsChild<ttype>(TType child, TType parent)
{
Type enumType = typeof(TType);
Object[] attributeList = enumType.GetCustomAttributes
(typeof(StructuredAttribute), true);

if (attributeList.Length > 0)
{
StructuredAttribute attribute = (StructuredAttribute)attributeList[0];
int span = attribute.Span;
int parentIndex = (int)Convert.ChangeType(parent, typeof(int));
int childIndex = (int)Convert.ChangeType(child, typeof(int));
int index = childIndex / span;
return (index == parentIndex && childIndex != parentIndex);
}

return true;
}```

Another useful method that may be of interest to us is the `CreateList `method. It obviously creates a list of the child enumeration values under a particular parental value. It will also allow us to use the output list for the display or various cycle purposes. I can imagine an iterator here.

```public static List<ttype> CreateList<ttype>(TType parent)
{
List<ttype> result = new List<ttype>();
Type enumType = typeof (TType);
TType[] enumValues = (TType[]) Enum.GetValues(enumType);

foreach (TType enumValue in enumValues)
{
if (IsChild(enumValue, parent))
{
}
}

return result;
}```

## Some Examples of Use

This example took all I mentioned above and put it to use. It will dump the tree to a console output while making the levels indented.

```private static void DumpTree(AnimalKind parent, Int32 level)
{
foreach (AnimalKind animalKind in EnumUtility.CreateList(parent))
{
string caption = animalKind.ToString();
int width = caption.Length;
string output = caption.PadLeft(width + level, ' ');
Console.WriteLine(output);
DumpTree(animalKind, level + 1);
}
}

static void Main()
{
DumpTree(AnimalKind.Unknown, 0);
}```

## Possible Enhancements

1. As I said earlier in this article, I can imagine some kind of iterator (or perhaps an indexer) instead of the `CreateList `method.
2. The default indexing capabilities of enumerations can be widened by "inheriting" the enumeration from `ulong `type instead of default `uint`.
3. The utility can also be extended with any kind of structuring routine which suits your need such as retrieving the chain of parents for a particular value.

## Limitations

• The complex trees with many levels may find their limit because the indexing will reach the limit of enumeration (`ulong`). This limitation can be reduced by lowering the span value on the attribute, thus allowing to scale for the count of branches against the count of levels.
• It is recommended to use some default (zero) value which will then be used to retrieve the level one branches.

## Personal Note

I found these structured enumerations quite useful myself dealing with countless - now waiting to be structured - category enumerations. They cut the time needed to create the editable trees where the categories are distinguished from the instance items. Moreover, the enumeration is still one type in the end.

## History

• 2008-04-02: Missing example was added (Shall I ever get it right the first time?)
• 2008-04-02: Initial article posted

## Share

 Software Developer Czech Republic
Contacts: EMAIL - smartk8@gmail.com

## You may also be interested in...

 First PrevNext
 not used attribute Member 1023970413-Feb-17 23:04 Member 10239704 13-Feb-17 23:04
 I did it my way (Part 1) [modified] PIEBALDconsult10-Apr-08 17:22 PIEBALDconsult 10-Apr-08 17:22
 Re: I did it my way (Part 1) P.S. PIEBALDconsult24-Apr-08 9:52 PIEBALDconsult 24-Apr-08 9:52
 Oh, and... PIEBALDconsult10-Apr-08 15:40 PIEBALDconsult 10-Apr-08 15:40
 C# 3.0 extension methods version Smart K89-Apr-08 2:15 Smart K8 9-Apr-08 2:15
 Re: C# 3.0 extension methods version PIEBALDconsult10-Apr-08 14:24 PIEBALDconsult 10-Apr-08 14:24
 Clarify presentation Seth Morris8-Apr-08 13:33 Seth Morris 8-Apr-08 13:33
 Re: Clarify presentation [modified] Smart K89-Apr-08 0:40 Smart K8 9-Apr-08 0:40
 Suggestions [modified] PIEBALDconsult6-Apr-08 17:20 PIEBALDconsult 6-Apr-08 17:20
 Suggestions Part 2 PIEBALDconsult6-Apr-08 18:11 PIEBALDconsult 6-Apr-08 18:11
 Re: Suggestions Part 2 Smart K86-Apr-08 19:43 Smart K8 6-Apr-08 19:43
 PIEBALDconsult wrote:In your Attribute, I suggest that the field and/or property should not be publicly modifiable. I missed that. I've got much bigger class EnumUtility I've just stripped away all the code non-concerned in the article. So the compromise: ```
private int span = 10; // or 0xF maybe

public int Span
{
get { return span; }
}
```PIEBALDconsult wrote:```public static bool IsChild(TType child, TType parent) // Where if ttype used? { Type enumType = typeof(TType); // This is needless Object[] attributeList = enumType.GetCustomAttributes(typeof(StructuredAttribute), true); if (attributeList.Length > 0) { StructuredAttribute attribute = (StructuredAttribute)attributeList[0]; int span = attribute.Span; // This is needless int parentIndex = (int)Convert.ChangeType(parent, typeof(int)); int childIndex = (int)Convert.ChangeType(child, typeof(int)); int index = childIndex / span; // You can simply use attribute.Span here return (index == parentIndex && childIndex != parentIndex); } return true; }``` Where if ttype used?: There's no constraint for Enum (it is not possible by C# design) moreover the Attribute is enum only so it ensures that TType will be Enum because otherwise the GetCustomAttributes will be zero. This is needless: This is my coding pattern of choice (substition pattern) it is IMO more readable then putting altogether (cumulative pattern). Consider this :`
return (((int)Convert.ChangeType(child, typeof(int)) / attribute.Span) ==
((int)Convert.ChangeType(parent, typeof(int)) &&
((int)Convert.ChangeType(child, typeof(int) != (int)Convert.ChangeType(parent, typeof(int));

`PIEBALDconsult wrote:`foreach (StructuredAttribute attribute in typeof(TType).GetCustomAttributes(typeof(StructuredAttribute), true))` Fine with me. PIEBALDconsult wrote:And, your CreateList calls GetValues on each call; which isn't as costly, but shouldn't be necessary. I guess there should be some common private class determining the paternity. Such as bool (TType child, TType parent, int span) I'll hear more of your comments and after that I'll modify the article accordingly. regards, Kate The wisdom is to see things truthfully.
 Re: Suggestions Part 2 PIEBALDconsult7-Apr-08 13:42 PIEBALDconsult 7-Apr-08 13:42
 Re: Suggestions Part 2 Smart K87-Apr-08 20:43 Smart K8 7-Apr-08 20:43
 Too complex PIEBALDconsult2-Apr-08 10:54 PIEBALDconsult 2-Apr-08 10:54
 P.S. Too complex PIEBALDconsult2-Apr-08 11:09 PIEBALDconsult 2-Apr-08 11:09
 Re: P.S. Too complex Smart K82-Apr-08 11:31 Smart K8 2-Apr-08 11:31
 Re: P.S. Too complex PIEBALDconsult2-Apr-08 11:35 PIEBALDconsult 2-Apr-08 11:35
 Re: P.S. Too complex Smart K82-Apr-08 11:44 Smart K8 2-Apr-08 11:44
 Re: P.S. Too complex PIEBALDconsult2-Apr-08 12:42 PIEBALDconsult 2-Apr-08 12:42
 Re: P.S. Too complex [modified] Smart K82-Apr-08 19:29 Smart K8 2-Apr-08 19:29
 Re: P.S. Too complex PIEBALDconsult2-Apr-08 14:26 PIEBALDconsult 2-Apr-08 14:26
 Reinventing the wheel `leppie`2-Apr-08 10:17 `leppie` 2-Apr-08 10:17
 Re: Reinventing the wheel Smart K82-Apr-08 10:35 Smart K8 2-Apr-08 10:35
 Re: Reinventing the wheel `leppie`2-Apr-08 11:10 `leppie` 2-Apr-08 11:10
 Re: Reinventing the wheel Smart K82-Apr-08 11:35 Smart K8 2-Apr-08 11:35
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Mar-18 3:54 Refresh 12 Next »