I am facing problem when I am trying to create dictionary, where key is System.Enum. Problem is, that dictionary like this allocates garbage because default EqualityComparer is not one of the best. I tryed to write my own comparer, but without any success. Is it somehow possible?
public enum MyEnum
{
One, Two, Three
}
public Dictionary<Enum, string> dict = new Dictionary<Enum, string>();
public void Test()
{
this.dict.Add(MyEnum.One, "One");
this.dict.Add(MyEnum.Two, "Two");
this.dict.Add(MyEnum.Three, "Three");
string result;
this.dict.TryGetValue(MyEnum.Two, out result); // <-- memory alocation :-(
}
No boxing, no heap allocations. Very fast. No need to write a specific comparer for each enum.
This version will work on any enum as long as its underlying Type isn't more than 32-bits (so byte, ushort, uint are all fine).
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public sealed class EnumComparer<T> : IEqualityComparer<T>
{
[StructLayout(LayoutKind.Explicit)]
private struct Transformer
{
[FieldOffset(0)]
public T t;
[FieldOffset(0)]
public int int32;
}
public static EnumComparer<T> Default { get; } = new EnumComparer<T>();
private EnumComparer()
{
}
public bool Equals(T a, T b)
{
Transformer aTransformer = new Transformer { t = a };
Transformer bTransformer = new Transformer { t = b };
return aTransformer.int32 == bTransformer.int32;
}
public int GetHashCode(T value)
{
Transformer valueTransformer = new Transformer { t = value };
return valueTransformer.int32.GetHashCode();
}
}
If you want to use it with arrays, you'll probably want to make some extension methods and then you can use it like this:
bool contained = enumArray.Contains(MyEnum.someValue, EnumComparer<MyEnum>.Default);
public static class Extensions
{
public static bool Contains<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer) >= 0;
}
public static int IndexOf<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer);
}
public static int IndexOf<T>(this T[] array, T value, int startIndex, int count, IEqualityComparer<T> equalityComparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (count < 0 || startIndex < array.GetLowerBound(0) || startIndex - 1 > array.GetUpperBound(0) - count)
{
throw new ArgumentOutOfRangeException();
}
int num = startIndex + count;
for (int i = startIndex; i < num; i++)
{
if (equalityComparer.Equals(array[i], value))
{
return i;
}
}
return -1;
}
}
Seeing your example in the comments, and that this is for Unity, watch this clip from Unite 2016. It talks about using Scriptable Objects instead of enums for dictionary keys.
What you would do is have
public class Program
{
protected Dictionary<ScriptableObject, string> dict = new Dictionary<ScriptableObject, string>();
}
public class ProgramChild1 : Program
{
public void Test()
{
dict.Add(MyEnum1.One.Instance, "One");
dict.Add(MyEnum1.Two.Instance, "Two");
dict.Add(MyEnum1.Three.Instance, "Three");
string result;
dict.TryGetValue(MyEnum1.Two.Instance, out result);
}
}
public class ProgramChild2 : Program
{
public void Test()
{
dict.Add(MyEnum2.Four.Instance, "One");
dict.Add(MyEnum2.Five.Instance, "Two");
dict.Add(MyEnum2.Six.Instance, "Three");
string result;
dict.TryGetValue(MyEnum2.Five.Instance, out result);
}
}
//Each class goes in to its own .cs file, Put them in two folders `MyEnum1` and `MyEnum2`
namespace MyEnum1
{
public class One : ScriptableObject
{
private static One _inst;
public static One Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<One>();
if (!_inst)
_inst = CreateInstance<One>();
return _inst;
}
}
}
}
namespace MyEnum1
{
public class Two : ScriptableObject
{
private static Two _inst;
public static Two Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Two>();
if (!_inst)
_inst = CreateInstance<Two>();
return _inst;
}
}
}
}
namespace MyEnum1
{
public class Three : ScriptableObject
{
private static Three _inst;
public static Three Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Three>();
if (!_inst)
_inst = CreateInstance<Three>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Four : ScriptableObject
{
private static Four_inst;
public static Four Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Four>();
if (!_inst)
_inst = CreateInstance<Four>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Five : ScriptableObject
{
private static Five _inst;
public static Five Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Five>();
if (!_inst)
_inst = CreateInstance<Five>();
return _inst;
}
}
}
}
namespace MyEnum2
{
public class Six : ScriptableObject
{
private static Six _inst;
public static Six Instance
{
get
{
if (!_inst)
_inst = Resources.FindObjectOfType<Six>();
if (!_inst)
_inst = CreateInstance<Six>();
return _inst;
}
}
}
}
Note that the reason we inherit from ScriptableObject is if you wanted to expose a enum to the designer you could then drag and drop the enum value right in the designer, you could not do this if the enums where just basic classes.
public class ProgramChild2 : Program
{
public ScriptableObject SelectedValue;
public void Test()
{
dict.Add(MyEnum2.Four.Instance, "One");
dict.Add(MyEnum2.Five.Instance, "Two");
dict.Add(MyEnum2.Six.Instance, "Three");
string result;
dict.TryGetValue(SelectedValue, out result);
}
}
You should write a class that implements the interface IEqualityComparer.
class MyEnumComparer : IEqualityComparer<MyEnum> { ... }
Which means you need to implement both bool Equals(MyEnum, MyEnum) and int GetHashCode(MyEnum) functions defined by the IEqualityComparer interface.
Finally when you are creating your Dictionary, use the constructor overload that receives an IEqualityComparer instance, like this:
static MyEnumComparer myEnumComparer = new MyEnumComparer();
...
Dictionary<MyEnum, string> dict = new Dictionary<MyEnum, string>(myEnumComparer);
Solution proposed by #Executor do not work on .Net framework or .Net Core
because of this Why can't generic types have explicit layout?
But if replace EnumComparer<T> from this solution with ConvertToLong from Dissecting new generic constraints in C# 7.3 it will give solution working on full frameworks.
Related
I have these multiple enums used as Ids and want to use them in a single list.
public enum eUnit
{
Villager,
Warrior,
Wizard,
}
public enum eVehicle
{
Car,
Train,
Helicopter,
}
public enum eItem
{
Apple,
Steak,
Pizza,
}
Is something like the code below possible?
List<?enum?> myList = new List<?enum?>();
myList.Add(eUnit.Warrior);
myList.Add(eItem.Pizza);
if(myList[0].GetType() == typeof(eUnit))
DoStuff();
...
...
Other way is to use a discriminated union via OneOf library.
var myList = new List<OneOf<eUnit, eVehicle, eItem>>()
{
eUnit.Warrior, eVehicle.Car
};
myList[0].Switch(
unit => Console.WriteLine("Unit"),
vehicle => Console.WriteLine("Vehicle"),
item => Console.WriteLine("Item")
);
I made a sample
You could try using the type dynamic. Perhaps it would be overkill but it is up to you.
You can implement your own List<T>. Here is a simple example :
public class EnumList
{
private readonly List<Entry> _entriesList = new List<Entry>();
public object this[int index]
{
get
{
var item = _entriesList[index];
return Enum.Parse(item.Key, item.Value);
}
set
{
_entriesList[index] = new Entry(value.GetType(), value.ToString());
}
}
private class Entry
{
public Type Key { get; set; }
public string Value { get; set; }
public Entry(Type key, string value)
{
Key = key;
Value = value;
}
}
public void Add<TEnum>(TEnum item) where TEnum : struct, Enum
{
_entriesList.Add(new Entry(typeof(TEnum), item.ToString()));
}
public List<TEnum> Get<TEnum>() where TEnum : struct, Enum
{
return _entriesList.Where(x => x.Key == typeof(TEnum)).Select(x => Enum.TryParse(x.Value, out TEnum result) ? result : default).ToList();
}
public bool Exists<TEnum>(TEnum item) where TEnum : struct, Enum
{
return _entriesList.Any(x => x.Key == typeof(TEnum) && x.Value == item.ToString());
}
}
Usage :
var list = new EnumList();
list.Add(eUnit.Warrior);
list.Add(eItem.Pizza);
list.Add(eVehicle.Car);
list.Add(eVehicle.Helicopter);
list.Add(eUnit.Villager);
list.Add(eItem.Apple);
if((eUnit)list[0] == eUnit.Warrior || list.Exists(eUnit.Villager))
{
// do stuff
}
This is just a sample to help you implement your own, remember, you should always try to narrow the acceptable params by specifying the intended enums, you could go full generic though.
As mentioned by Andriy, using a discriminated union such as the OneOf, or Either can be useful in this case.
If you are just using the enums as an ID, you could also create various classes and utilize the type system for pattern matching. This is just a different pattern you could look into if you like pattern matching against specific items.
internal abstract class EnumType
{
protected EnumType(int value, string name)
{
if(value < 0) { throw new InvalidOperationException("Value cannot be less than 0."); }
this._value = value;
this._name = name ?? throw new ArgumentNullException(nameof(name));
}
public static implicit operator int(EnumType x)
=> x?._value ?? throw new ArgumentNullException(nameof(x));
public static implicit operator string(EnumType x)
=> x?._name ?? throw new ArgumentNullException(nameof(x));
private readonly int _value;
private readonly string _name;
}
internal sealed class eUnit : EnumType
{
private eUnit(int value, string name): base(value, name) { }
// operator overloads like |, &, ^, etc...
internal static readonly eUnit Villager = new eUnit(0, "Villager");
internal static readonly eUnit Warrior = new eUnit(1, "Warrior");
internal static readonly eUnit Wizard = new eUnit(2, "Wizard");
}
internal sealed class eItem : EnumType
{
private eItem(int value, string name): base(0, "Apple") { }
// operator overloads like |, &, ^, etc...
internal static readonly eItem Apple = new eItem(0, "Apple");
internal static readonly eItem Steak = new eItem(1, "Steak");
internal static readonly eItem Pizza = new eItem(2, "Pizza");
}
This would allow you to then write:
var myList = new List<EnumType>();
myList.Add(eUnit.Warrior);
myList.Add(eItem.Pizza);
if (myList[0] is eUnit eUnit)
{
DoStuff();
}
If you cared about further granularity, you could turn those static fields into classes as well, along the lines of:
internal abstract class eUnit : EnumType
{
private eUnit(int value, string name): base(value, name) { }
// operator overloads like |, &, ^, etc...
internal sealed class Villager : eUnit
{
private Villager(): base(0, "Villager") { }
internal static readonly Villager _ = new Villager();
}
internal sealed class Warrior : eUnit
{
private Warrior(): base(1, "Warrior") { }
internal static readonly Warrior _ = new Warrior();
}
internal sealed class Wizard : eUnit
{
private Wizard(): base(2, "Wizard") { }
internal static readonly Wizard _ = new Wizard();
}
}
internal abstract class eItem : EnumType
{
private eItem(int value, string name): base(0, "Apple") { }
// operator overloads like |, &, ^, etc...
//...
internal sealed class Pizza : eItem
{
private Pizza(): base(2, "Pizza") { }
internal static readonly Pizza _ = new Pizza();
}
}
Then your sample would be rewritten as:
var myList = new List<EnumType>();
myList.Add(eUnit.Warrior._);
myList.Add(eItem.Pizza._);
var result = myList[0] switch
{
eUnit eUnit => eUnit switch
{
eUnit.Villager villager => DoVillagerStuff(villager),
eUnit.Warrior warrior => DoWarriorStuff(warrior),
eUnit.Wizard wizard => DoWizardStuff(wizard),
_ => throw new InvalidOperationException("Unknonwn eItem");
},
eItem eItem = eItem switch
{
eItem.Pizza pizza => DoPizzaStuff(pizza),
_ => throw new InvalidOperationException("Unsupported eItem")
}
};
You could have a look at the ArrayList class:
public enum eUnit
{
Villager,
Warrior,
Wizard,
}
public enum eVehicle
{
Car,
Train,
Helicopter,
}
public enum eItem
{
Apple,
Steak,
Pizza,
}
void Main()
{
var myList = new ArrayList();
myList.Add(eUnit.Warrior);
myList.Add(eItem.Pizza);
for (int i = 0; i < myList.Count; i++)
{
var element = myList[i];
if (element is eUnit unit)
Console.WriteLine($"Element at index {i} is eUnit {unit}");
else if (element is eVehicle vehicle)
Console.WriteLine($"Element at index {i} is eVehicle {vehicle}");
else if (element is eItem item)
Console.WriteLine($"Element at index {i} is eItem {item}");
else
Console.WriteLine($"Element at index {i} is another type");
}
}
I want to write a generic class that accepts enumerations. Since this class is intended to implement some interfaces, the main aim is to be able to treat enumerations as other objects implementing those interfaces(e.g. for list extensions, etc). Hence, for a sample enum
public enum QEnum : int
{
xlNoValue = 0,
xlSomeValue = 1
}
public static class QEnumExtensions
{
public static string toString(this QEnum xThis)
{
...
}
public static QEnum toEnum(this string xThis)
{
...
}
}
I would like to declare a generic class such as
public class QEnumHolder<T> where T : struct, IConvertible
{
private T mxVal = default(T);
public QEnumHolder()
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
}
public QEnumHolder(T xVal)
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
mxVal = xVal;
}
static public implicit operator QEnumHolder<T>(T xVal)
{
return new QEnumHolder<T>(xVal);
}
static public implicit operator T(QEnumHolder<T> xVal)
{
return (T)xVal.mxVal;
}
public string toString()
{
if (mxVal is QEnum) return ((QEnum)Convert.ToInt32(mxVal)).toString();
...
}
public void fromString(string xString)
{
if (mxVal is QEnum)
mxVal = (???)xString.toEnum(); // problem
}
}
All of the enumerations that we use implement
toString() function which returns a "nice" string that can go into comboBoxes, etc
conversion of string to enumeration, as above
hence the structure of toString/toEnum is pretty much given. The problem is with the last code line marked "problem". I have no idea how to tell the compiler that in this branch, the return type of toEnum() and T will be the same.
I tried to circumvent the problem by declaring mxVal as int and using Convert.ToInt32 everywhere. However, then I run into problem in the operator T where the compiler has objections against converting int to a T (the compiler can't know that T will be enum, hence I can't use none of the "int to enum conversion" discussions here on SO).
A better design would be to use some naming convention, put all your enum extension methods in one and the same static class, and bind these functions inside your holder class static constructor. Something like this:
public static partial class MyEnumExtensions
{
public static MyEnumHolder<T> ToHolder<T>(this T source)
where T : struct, IConvertible
{
return new MyEnumHolder<T>(source);
}
}
public class MyEnumHolder<T> where T : struct, IConvertible
{
static readonly Func<T, string> toStringFunc;
static readonly Func<string, T> toEnumFunc;
static MyEnumHolder()
{
if (!typeof(T).IsEnum) throw new NotSupportedException();
// Use your naming conventions
var name = typeof(T).Name;
toStringFunc = (Func<T, string>)Delegate.CreateDelegate(typeof(Func<T, string>),
typeof(MyEnumExtensions).GetMethod("toString", new[] { typeof(T) }));
toEnumFunc = (Func<string, T>)Delegate.CreateDelegate(typeof(Func<string, T>),
typeof(MyEnumExtensions).GetMethod("to" + name, new[] { typeof(string) }));
}
private T value;
public MyEnumHolder() { value = default(T); }
public MyEnumHolder(T value) { this.value = value; }
static public implicit operator MyEnumHolder<T>(T x) { return new MyEnumHolder<T>(x); }
static public implicit operator T(MyEnumHolder<T> x) { return x.value; }
public string toString()
{
return toStringFunc(value);
}
public void fromString(string xString)
{
value = toEnumFunc(xString);
}
}
Sample enum definitions (could be in separate files, but must be inside the same project):
public enum MyEnumA { A1, A2, A3 }
partial class MyEnumExtensions
{
public static string toString(this MyEnumA x)
{
//...
return x.ToString();
}
public static MyEnumA toMyEnumA(this string x)
{
//...
return (MyEnumA)Enum.Parse(typeof(MyEnumA), x);
}
}
and
public enum MyEnumB { B1, B2, B3 }
partial class MyEnumExtensions
{
public static string toString(this MyEnumB x)
{
//...
return x.ToString();
}
public static MyEnumB toMyEnumB(this string x)
{
//...
return (MyEnumB)Enum.Parse(typeof(MyEnumB), x);
}
}
test:
var a = MyEnumA.A1.ToHolder();
var sA = a.toString();
a.fromString("A2");
var b = MyEnumB.B2.ToHolder();
var sB = b.toString();
b.fromString("B1");
mxVal = (T)(object)xString.toEnum();
I want to update a list of objects(mycapsule, has many other members) when a condition (pred) holds for one of its class members(value). Whenever I change something another thing fails, I'm newbie in C# and really confused.
Can somebody fix my code:
In the best condition I only get get this error but I think many things are missing in my code
The type or namespace name `T' could not be found. Are you missing a using directive or an assembly reference?
here is my code
using System;
using System.Collections.Generic ;
namespace test
{
class MainClass
{
public static List< mycapsule<int,double> > sample= new List< mycapsule<int,double>>();
public static void Main (string[] args)
{
sample.Add(new mycapsule<int,double> {id=1 , value= 1.2});
update(pred, 12.3);
}
public static bool pred(double x)
{
if (x==2.5) return true;
return false;
}
public class mycapsule<KT, T>
{
public KT id {get ; set; }
public T value { get ; set; }
public int p; // and more
}
public bool update(Func<T, bool> predicate, T i)
{
foreach (var x in sample.FindAll(item => predicate(JustValue(item))) )
{
x.value = i ;
}
return true ;
}
public T JustValue(mycapsule<int,T> i)
{
return i.value;
}
}
}
Look at your update method:
public bool update(Func<T, bool> predicate, T i)
{
foreach (var x in KeyRecord.FindAll(item => predicate(JustValue(item))) )
{
x.value = i ;
}
return true ;
}
What do you expect T to be here? The method is not generic (it's not written as update<T>) and it's not declared in a generic class.
It's possible that you just want:
public bool update<T>(Func<T, bool> predicate, T i)
... but it's hard to say without knowing what KeyRecord.FindAll looks like. Oh, and you've got the same problem with JustValue.
As a side issue, the method names update and pred don't follow .NET naming conventions, and JustValue is a poor method name in terms of descriptiveness. mycapsule also doesn't follow .NET naming conventions. These things really matter in terms of readability.
I'm afraid this won't work due to type safety reasons. I corrected the code as much as possible and got this:
public static List<mycapsule<int, double>> sample = new List<mycapsule<int, double>>();
public static void Main(string[] args)
{
sample.Add(new mycapsule<int, double> { id = 1, value = 1.2 });
update(pred, 12.3);
}
public static bool pred(double x)
{
if (x == 2.5) return true;
return false;
}
public class mycapsule<KT, T>
{
public KT id { get; set; }
public T value { get; set; }
public int p; // and more
}
public static bool update<T>(Func<T, bool> predicate, T i)
{
List<mycapsule<int, double>> list = sample.FindAll(item => predicate(JustValue(item)));
foreach (var x in list)
{
x.value = i;
}
return true;
}
public static T JustValue<T>(mycapsule<int, T> i)
{
return i.value;
}
The error is:
predicate(JustValue(item)) => Argument 1: cannot implicitly convert from double to T
This comes from the fact that you are trying to forcefully call a method that you've specified as taking a generic type T (Func<T, bool>) with a value that is known to be double. Although we know that T will be double from the call to update(pred, 12.3);, nothing prevents me from passing in a predicate that takes an incompatible type e.g.:
public static bool pred(string x)
{
return false;
}
and
update(pred, "asdf");
Which is clearly inconsistent. The compiler is simply trying to prevent you from shooting yourself in the foot accidentally.
To solve this, you could explicitly pass the collection to the update method, thus ensuring that the types are consistent:
public static List<mycapsule<int, double>> sample = new List<mycapsule<int, double>>();
public static void Main(string[] args)
{
sample.Add(new mycapsule<int, double> { id = 1, value = 1.2 });
update(pred, 12.5, sample);
}
public static bool pred(double x)
{
if (x == 2.5) return true;
return false;
}
public class mycapsule<KT, T>
{
public KT id { get; set; }
public T value { get; set; }
public int p; // and more
}
public static bool update<T>(Func<T, bool> predicate, T i, List<mycapsule<int, T>> list)
{
foreach (var x in list.FindAll(item => predicate(JustValue(item))))
{
x.value = i;
}
return true;
}
public static T JustValue<T>(mycapsule<int, T> i)
{
return i.value;
}
Try this, And for generic method the method definition you have used is not correct.
It should be
//MethodName<T,U>(T para1, U para2)
I have change the code to include reflections, this should work.
Please try and give feedback.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace test
{
class MainClass
{
public static List<Mycapsule<int, double>> sample = new List<Mycapsule<int, double>>();
public static void Main(string[] args)
{
sample.Add(new Mycapsule<int, double> { id = 1, value = 1.2 });
update(pred, 12.3);
}
public static bool pred(double x)
{
if (x == 2.5) return true;
return false;
}
public static bool update<T>(Func<T, bool> predicate, T i)
{
var myCollection = sample.FindAll(p => pred(JustValue<double>(p)));
MainClass mainClass = new MainClass();
foreach (var x in myCollection)
{
MethodInfo changeTypeMethod = typeof(MainClass).GetMethod("GetValue");
object value = changeTypeMethod.Invoke(mainClass, new object[] { i, typeof(T) });
PropertyInfo valueProperty = x.GetType().GetProperty("value");
valueProperty.SetValue(x, value);
}
return true;
}
public T GetValue<T>(T i)
{
return (T)Convert.ChangeType(i, typeof(T));
}
public static T JustValue<T>(Mycapsule<int, T> i)
{
return i.value;
}
}
//Outside the MainClass inside the same namespace
public class Mycapsule<KT, T>
{
public KT id { get; set; }
public T value { get; set; }
public int p; // and more
}
}
I have an abstract base class that holds a Dictionary. I'd like inherited classes to be able to access the dictionary fields using a convenient syntax. Currently I have lots of code like this:
string temp;
int val;
if (this.Fields.TryGetValue("Key", out temp)) {
if (int.TryParse(temp, out val)) {
// do something with val...
}
}
Obviously I can wrap this in utility functions but I'd like to have a cool, convenient syntax for accessing the dictionary fields where I can simply say something like:
int result = #Key;
Is there any way to do something like this in C# (3.5)?
You could add an indexer to your class and pass the indexer's parameter through to the dictionary.
class Foo
{
// Initialized elsewhere
Dictionary<String,String> Fields;
public Int32 this[String key]
{
String temp = null;
Int32 val = 0;
if (this.Fields.TryGetValue(key, out temp)) {
Int32.TryParse(temp, out val);
}
return val;
}
}
Then given an instance of Foo called foo you could do this:
Int32 value = foo["Key"];
How about an extension method?
public static int TryGetInt(this IDictionary dict, string key)
{
int val;
if (dict.Contains(key))
{
if (int.TryParse((string)dict[key], out val))
return val;
else
throw new Exception("Value is not a valid integer.");
}
throw new Exception("Key not found.");
}
The closer you can get to a nice syntax is using extension methods:
public static class MyDictExtensionMethods
{
public static T Get<T>(this Dictionary<string, object> dict, string key)
where T: IConvertible
{
object tmp;
if (!dict.TryGetValue(key, out tmp))
return default(T);
try {
return (T) Convert.ChangeType(tmp, typeof(T));
} catch (Exception) {
return default(T);
}
}
}
Usage:
int val = this.Fields.Get<int>("Key");
You can then create additional overloads for specific types (i.e.: types that does not implement IConvertible and need specific conversion).
Assuming that it's not always an int you want (if it is, then why isn't it a Dictionary<string, int>?) - I think something like this works and gets pretty close:
int i = #int["Key"];
string s = #string["Key"];
object o = #object["Key"];
This combines the fact that identifiers can be prefixed with # (it's usually optional, but it's required if your identifier is a reserved keyword, like int or string) with the default indexed parameter from Andrew Hare's answer.
It does require another class to be used to get the indexing - though if you wanted to use parens instead of square brackets for the key name, you could use methods instead:
int i = #value<int>("Key");
Implementation would be something like:
class DerivedClass : BaseClass {
void Main() {
int i = #int["Key"];
}
}
abstract class BaseClass {
private Dictionary<string, string> D { get; set; }
protected Indexer<int> #int = new Indexer<int>(s => int.Parse(s), this);
protected Indexer<string> #string = new Indexer<string>(s => s, this);
protected Indexer<object> #object = new Indexer<object>(s => (object)s, this);
protected class Indexer<T> {
public T this[string key] {
get { return this.Convert(this.BaseClass.D[key]); }
}
private T Convert(string value) { get; set; }
private BaseClass { get; set; }
public Indexer(Func<T, string> c, BaseClass b) {
this.Convert = c;
this.BaseClass = b;
}
}
}
Or, the method route:
class DerivedClass : BaseClass {
void Main() {
int i = #value<int>("key");
}
}
abstract class BaseClass {
private Dictionary<string, string> D { get; set; }
protected T #value<T>(string key) {
string s = this.D[s];
return Convert.ChangeType(s, typeof(T));
}
}
After reading through the language spec - if you're not tied to #, _ is a legal identifier. Combine that with indexers and you get:
int i = _["key"];
This question already has answers here:
C# vs Java Enum (for those new to C#)
(13 answers)
Closed 9 years ago.
What's the equivalent of Java's enum in C#?
Full Java enum functionality isn't available in C#. You can come reasonably close using nested types and a private constructor though. For example:
using System;
using System.Collections.Generic;
using System.Xml.Linq;
public abstract class Operator
{
public static readonly Operator Plus = new PlusOperator();
public static readonly Operator Minus =
new GenericOperator((x, y) => x - y);
public static readonly Operator Times =
new GenericOperator((x, y) => x * y);
public static readonly Operator Divide =
new GenericOperator((x, y) => x / y);
// Prevent other top-level types from instantiating
private Operator()
{
}
public abstract int Execute(int left, int right);
private class PlusOperator : Operator
{
public override int Execute(int left, int right)
{
return left + right;
}
}
private class GenericOperator : Operator
{
private readonly Func<int, int, int> op;
internal GenericOperator(Func<int, int, int> op)
{
this.op = op;
}
public override int Execute(int left, int right)
{
return op(left, right);
}
}
}
Of course you don't have to use nested types, but they give the handy "custom behaviour" part which Java enums are nice for. In other cases you can just pass arguments to a private constructor to get a well-known restricted set of values.
A few things this doesn't give you:
Ordinal support
Switch support
EnumSet
Serialization/deserialization (as a singleton)
Some of that could probably be done with enough effort, though switch wouldn't really be feasible without hackery. Now if the language did something like this, it could do interesting things to make switch work by making the hackery automatic (e.g. declaring a load of const fields automatically, and changing any switch over the enum type to a switch over integers, only allowing "known" cases .)
Oh, and partial types mean you don't have to have all of the enum values in the same file. If each value got quite involved (which is definitely possible) each could have its own file.
Enums are one of the few language features that is better implemented in java than c#.
In java, enums are full fledged named instances of a type, while c# enums are basically named constants.
That being said, for the basic case, they will look similar. However in java, you have more power, in that you can add behavior to the individual enums, as they are full fledged classes.
is there some feature in particular you are looking for?
Here's another interesting idea. I came up with the following Enumeration base class:
public abstract class Enumeration<T>
where T : Enumeration<T>
{
protected static int nextOrdinal = 0;
protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>();
protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>();
protected readonly string name;
protected readonly int ordinal;
protected Enumeration(string name)
: this (name, nextOrdinal)
{
}
protected Enumeration(string name, int ordinal)
{
this.name = name;
this.ordinal = ordinal;
nextOrdinal = ordinal + 1;
byOrdinal.Add(ordinal, this);
byName.Add(name, this);
}
public override string ToString()
{
return name;
}
public string Name
{
get { return name; }
}
public static explicit operator int(Enumeration<T> obj)
{
return obj.ordinal;
}
public int Ordinal
{
get { return ordinal; }
}
}
It's got a type parameter basically just so the ordinal count will work properly across different derived enumerations. Jon's Operator example above then becomes:
public class Operator : Enumeration<Operator>
{
public static readonly Operator Plus = new Operator("Plus", (x, y) => x + y);
public static readonly Operator Minus = new Operator("Minus", (x, y) => x - y);
public static readonly Operator Times = new Operator("Times", (x, y) => x * y);
public static readonly Operator Divide = new Operator("Divide", (x, y) => x / y);
private readonly Func<int, int, int> op;
// Prevent other top-level types from instantiating
private Operator(string name, Func<int, int, int> op)
:base (name)
{
this.op = op;
}
public int Execute(int left, int right)
{
return op(left, right);
}
}
This gives a few advantages.
Ordinal support
Conversion to string and int which makes switch statements feasible
GetType() will give the same result for each of the values of a derived Enumeration type.
The Static methods from System.Enum can be added to the base Enumeration class to allow the same functionality.
You could probably use the old typesafe enum pattern that we used in Java before we got real ones (assuming that the ones in C# really aren't classes as a comment claims). The pattern is described just before the middle of this page
//Review the sample enum below for a template on how to implement a JavaEnum.
//There is also an EnumSet implementation below.
public abstract class JavaEnum : IComparable {
public static IEnumerable<JavaEnum> Values {
get {
throw new NotImplementedException("Enumeration missing");
}
}
public readonly string Name;
public JavaEnum(string name) {
this.Name = name;
}
public override string ToString() {
return base.ToString() + "." + Name.ToUpper();
}
public int CompareTo(object obj) {
if(obj is JavaEnum) {
return string.Compare(this.Name, ((JavaEnum)obj).Name);
} else {
throw new ArgumentException();
}
}
//Dictionary values are of type SortedSet<T>
private static Dictionary<Type, object> enumDictionary;
public static SortedSet<T> RetrieveEnumValues<T>() where T : JavaEnum {
if(enumDictionary == null) {
enumDictionary = new Dictionary<Type, object>();
}
object enums;
if(!enumDictionary.TryGetValue(typeof(T), out enums)) {
enums = new SortedSet<T>();
FieldInfo[] myFieldInfo = typeof(T).GetFields(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
foreach(FieldInfo f in myFieldInfo) {
if(f.FieldType == typeof(T)) {
((SortedSet<T>)enums).Add((T)f.GetValue(null));
}
}
enumDictionary.Add(typeof(T), enums);
}
return (SortedSet<T>)enums;
}
}
//Sample JavaEnum
public class SampleEnum : JavaEnum {
//Enum values
public static readonly SampleEnum A = new SampleEnum("A", 1);
public static readonly SampleEnum B = new SampleEnum("B", 2);
public static readonly SampleEnum C = new SampleEnum("C", 3);
//Variables or Properties common to all enums of this type
public int int1;
public static int int2 = 4;
public static readonly int int3 = 9;
//The Values property must be replaced with a call to JavaEnum.generateEnumValues<MyEnumType>() to generate an IEnumerable set.
public static new IEnumerable<SampleEnum> Values {
get {
foreach(var e in JavaEnum.RetrieveEnumValues<SampleEnum>()) {
yield return e;
}
//If this enum should compose several enums, add them here
//foreach(var e in ChildSampleEnum.Values) {
// yield return e;
//}
}
}
public SampleEnum(string name, int int1)
: base(name) {
this.int1 = int1;
}
}
public class EnumSet<T> : SortedSet<T> where T : JavaEnum {
// Creates an enum set containing all of the elements in the specified element type.
public static EnumSet<T> AllOf(IEnumerable<T> values) {
EnumSet<T> returnSet = new EnumSet<T>();
foreach(T item in values) {
returnSet.Add(item);
}
return returnSet;
}
// Creates an enum set with the same element type as the specified enum set, initially containing all the elements of this type that are not contained in the specified set.
public static EnumSet<T> ComplementOf(IEnumerable<T> values, EnumSet<T> set) {
EnumSet<T> returnSet = new EnumSet<T>();
foreach(T item in values) {
if(!set.Contains(item)) {
returnSet.Add(item);
}
}
return returnSet;
}
// Creates an enum set initially containing all of the elements in the range defined by the two specified endpoints.
public static EnumSet<T> Range(IEnumerable<T> values, T from, T to) {
EnumSet<T> returnSet = new EnumSet<T>();
if(from == to) {
returnSet.Add(from);
return returnSet;
}
bool isFrom = false;
foreach(T item in values) {
if(isFrom) {
returnSet.Add(item);
if(item == to) {
return returnSet;
}
} else if(item == from) {
isFrom = true;
returnSet.Add(item);
}
}
throw new ArgumentException();
}
// Creates an enum set initially containing the specified element(s).
public static EnumSet<T> Of(params T[] setItems) {
EnumSet<T> returnSet = new EnumSet<T>();
foreach(T item in setItems) {
returnSet.Add(item);
}
return returnSet;
}
// Creates an empty enum set with the specified element type.
public static EnumSet<T> NoneOf() {
return new EnumSet<T>();
}
// Returns a copy of the set passed in.
public static EnumSet<T> CopyOf(EnumSet<T> set) {
EnumSet<T> returnSet = new EnumSet<T>();
returnSet.Add(set);
return returnSet;
}
// Adds a set to an existing set.
public void Add(EnumSet<T> enumSet) {
foreach(T item in enumSet) {
this.Add(item);
}
}
// Removes a set from an existing set.
public void Remove(EnumSet<T> enumSet) {
foreach(T item in enumSet) {
this.Remove(item);
}
}
}
enum , or do you need something in particular that Java enums have but c# doesn't ?