Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to implement a Rust enum in C#?

Tags:

c#

enums

I have an entity that can be in one of different states (StateA, StateB and StateC), and in each of them have relevant data of distinct types (TStateA, TStateB, TStateC). Enums in Rust represent this perfectly. What is the best way to implement something like this in C#?

This question may appear similar, but enums in Rust and unions in C are significantly different.

like image 330
Max Yankov Avatar asked Jul 01 '15 15:07

Max Yankov


People also ask

How do you create an enum in Rust?

To declare an enumeration, we write the enum keyword, followed by a unique name and a code block. Inside the code block we declare our actual words that will map to numbers, separated by commas. Enums in Rust are conventionally written with pascal case.

What are enums in programming?

An enumeration, or Enum , is a symbolic name for a set of values. Enumerations are treated as data types, and you can use them to create sets of constants for use with variables and properties.

How do you convert enum to string in Rust?

The easiest way to convert an enum to a String in Rust is to implement the std::fmt::Display trait. Then you can call the to_string() method.

Can we create enum inside the class C#?

In the C# language, enum (also called enumeration) is a user-defined value type used to represent a list of named integer constants. It is created using the enum keyword inside a class, structure, or namespace. It improves a program's readability, maintainability and reduces complexity.


2 Answers

You need a class to represent your Entity

class Entity {States state;}

Then you need a set of classes to represent your states.

abstract class States {
   // maybe something in common
}
class StateA : MyState {
   // StateA's data and methods
}
class StateB : MyState {
   // ...
}

Then you need to write code like

StateA maybeStateA = _state as StateA;
If (maybeStateA != null)
{
    - do something with the data in maybeStateA
}

C# does not have a nice way of writing code for this yet, maybe the Pattern Matching that is being considered for C#.next would help.

I think you should rethink your design to use object relationships and containment, trying to take a design that works in rust and force it into C# may not be the best option.

like image 191
Ian Ringrose Avatar answered Oct 01 '22 21:10

Ian Ringrose


This might be crazy, but if you are hard-up about emulating Rust-like enums in C#, you could do it with some generics. Bonus: you keep type-safety and also get Intellisense out of the deal! You'll lose a little flexibility with various value types, but I think the safety is probably worth the inconvenience.

enum Option
{
    Some,
    None
}

class RustyEnum<TType, TValue>
{
    public TType EnumType { get; set; }
    public TValue EnumValue { get; set; }
}

// This static class basically gives you type-inference when creating items. Sugar!
static class RustyEnum
{
    // Will leave the value as a null `object`. Not sure if this is actually useful.
    public static RustyEnum<TType, object> Create<TType>(TType e)
    {
        return new RustyEnum<TType, object>
        {
            EnumType = e,
            EnumValue = null
        };
    }

    // Will let you set the value also
    public static RustyEnum<TType, TValue> Create<TType, TValue>(TType e, TValue v)
    {
        return new RustyEnum<TType, TValue>
        {
            EnumType = e,
            EnumValue = v
        };
    }
}

void Main()
{
    var hasSome = RustyEnum.Create(Option.Some, 42);
    var hasNone = RustyEnum.Create(Option.None, 0);

    UseTheEnum(hasSome);
    UseTheEnum(hasNone);
}

void UseTheEnum(RustyEnum<Option, int> item)
{
    switch (item.EnumType)
    {
        case Option.Some:
            Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
            break;
        default:
            Debug.WriteLine("You know nuffin', Jon Snow!");
            break;
    }
}

Here's another sample demonstrating the use of a custom reference type.

class MyComplexValue
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }

    public override string ToString()
    {
        return string.Format("A: {0}, B: {1}, C: {2}", A, B, C);
    }
}

void Main()
{
    var hasSome = RustyEnum.Create(Option.Some, new MyComplexValue { A = 1, B = 2, C = 3});
    var hasNone = RustyEnum.Create(Option.None, null as MyComplexValue);

    UseTheEnum(hasSome);
    UseTheEnum(hasNone);
}

void UseTheEnum(RustyEnum<Option, MyComplexValue> item)
{
    switch (item.EnumType)
    {
        case Option.Some:
            Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
            break;
        default:
            Debug.WriteLine("You know nuffin', Jon Snow!");
            break;
    }
}
like image 43
jocull Avatar answered Oct 01 '22 20:10

jocull