I want to do the same as in this question, that is:
enum DaysOfTheWeek {Sunday=0, Monday, Tuesday...};
string[] message_array = new string[number_of_items_at_enum];
...
Console.Write(custom_array[(int)DaysOfTheWeek.Sunday]);
however, I would rather have something integral to so, rather than write this error prone code. Is there a built in module in C# that does just this?
If the values of your enum items are contigious, the array method works pretty well. However, in any case, you could use Dictionary<DayOfTheWeek, string> (which is less performant, by the way).
Since C# 7.3 it has been possible to use System.Enum as a constraint on type parameters. So the nasty hacks in the some of the other answers are no longer required.
Here's a very simple ArrayByEum class that does exactly what the question asked.
Note that it will waste space if the enum values are non-contiguous, and won't cope with enum values that are too large for an int. I did say this example was very simple.
/// <summary>An array indexed by an Enum</summary>
/// <typeparam name="T">Type stored in array</typeparam>
/// <typeparam name="U">Indexer Enum type</typeparam>
public class ArrayByEnum<T,U> : IEnumerable where U : Enum // requires C# 7.3 or later
{
private readonly T[] _array;
private readonly int _lower;
public ArrayByEnum()
{
_lower = Convert.ToInt32(Enum.GetValues(typeof(U)).Cast<U>().Min());
int upper = Convert.ToInt32(Enum.GetValues(typeof(U)).Cast<U>().Max());
_array = new T[1 + upper - _lower];
}
public T this[U key]
{
get { return _array[Convert.ToInt32(key) - _lower]; }
set { _array[Convert.ToInt32(key) - _lower] = value; }
}
public IEnumerator GetEnumerator()
{
return Enum.GetValues(typeof(U)).Cast<U>().Select(i => this[i]).GetEnumerator();
}
}
Usage:
ArrayByEnum<string,MyEnum> myArray = new ArrayByEnum<string,MyEnum>();
myArray[MyEnum.First] = "Hello";
myArray[YourEnum.Other] = "World"; // compiler error
You could make a class or struct that could do the work for you
public class Caster
{
public enum DayOfWeek
{
Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public Caster() {}
public Caster(string[] data) { this.Data = data; }
public string this[DayOfWeek dow]{
get { return this.Data[(int)dow]; }
}
public string[] Data { get; set; }
public static implicit operator string[](Caster caster) { return caster.Data; }
public static implicit operator Caster(string[] data) { return new Caster(data); }
}
class Program
{
static void Main(string[] args)
{
Caster message_array = new string[7];
Console.Write(message_array[Caster.DayOfWeek.Sunday]);
}
}
EDIT
For lack of a better place to put this, I am posting a generic version of the Caster class below. Unfortunately, it relies on runtime checks to enforce TKey as an enum.
public enum DayOfWeek
{
Weekend,
Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public class TypeNotSupportedException : ApplicationException
{
public TypeNotSupportedException(Type type)
: base(string.Format("The type \"{0}\" is not supported in this context.", type.Name))
{
}
}
public class CannotBeIndexerException : ApplicationException
{
public CannotBeIndexerException(Type enumUnderlyingType, Type indexerType)
: base(
string.Format("The base type of the enum (\"{0}\") cannot be safely cast to \"{1}\".",
enumUnderlyingType.Name, indexerType)
)
{
}
}
public class Caster<TKey, TValue>
{
private readonly Type baseEnumType;
public Caster()
{
baseEnumType = typeof(TKey);
if (!baseEnumType.IsEnum)
throw new TypeNotSupportedException(baseEnumType);
}
public Caster(TValue[] data)
: this()
{
Data = data;
}
public TValue this[TKey key]
{
get
{
var enumUnderlyingType = Enum.GetUnderlyingType(baseEnumType);
var intType = typeof(int);
if (!enumUnderlyingType.IsAssignableFrom(intType))
throw new CannotBeIndexerException(enumUnderlyingType, intType);
var index = (int) Enum.Parse(baseEnumType, key.ToString());
return Data[index];
}
}
public TValue[] Data { get; set; }
public static implicit operator TValue[](Caster<TKey, TValue> caster)
{
return caster.Data;
}
public static implicit operator Caster<TKey, TValue>(TValue[] data)
{
return new Caster<TKey, TValue>(data);
}
}
// declaring and using it.
Caster<DayOfWeek, string> messageArray =
new[]
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
Console.WriteLine(messageArray[DayOfWeek.Sunday]);
Console.WriteLine(messageArray[DayOfWeek.Monday]);
Console.WriteLine(messageArray[DayOfWeek.Tuesday]);
Console.WriteLine(messageArray[DayOfWeek.Wednesday]);
Console.WriteLine(messageArray[DayOfWeek.Thursday]);
Console.WriteLine(messageArray[DayOfWeek.Friday]);
Console.WriteLine(messageArray[DayOfWeek.Saturday]);
Here you go:
string[] message_array = Enum.GetNames(typeof(DaysOfTheWeek));
If you really need the length, then just take the .Length on the result :)
You can get values with:
string[] message_array = Enum.GetValues(typeof(DaysOfTheWeek));
Compact form of enum used as index and assigning whatever type to a Dictionary
and strongly typed. In this case float values are returned but values could be complex Class instances having properties and methods and more:
enum opacityLevel { Min, Default, Max }
private static readonly Dictionary<opacityLevel, float> _oLevels = new Dictionary<opacityLevel, float>
{
{ opacityLevel.Max, 40.0 },
{ opacityLevel.Default, 50.0 },
{ opacityLevel.Min, 100.0 }
};
//Access float value like this
var x = _oLevels[opacitylevel.Default];
If all you need is essentially a map, but don't want to incur performance overhead associated with dictionary lookups, this might work:
public class EnumIndexedArray<TKey, T> : IEnumerable<KeyValuePair<TKey, T>> where TKey : struct
{
public EnumIndexedArray()
{
if (!typeof (TKey).IsEnum) throw new InvalidOperationException("Generic type argument is not an Enum");
var size = Convert.ToInt32(Keys.Max()) + 1;
Values = new T[size];
}
protected T[] Values;
public static IEnumerable<TKey> Keys
{
get { return Enum.GetValues(typeof (TKey)).OfType<TKey>(); }
}
public T this[TKey index]
{
get { return Values[Convert.ToInt32(index)]; }
set { Values[Convert.ToInt32(index)] = value; }
}
private IEnumerable<KeyValuePair<TKey, T>> CreateEnumerable()
{
return Keys.Select(key => new KeyValuePair<TKey, T>(key, Values[Convert.ToInt32(key)]));
}
public IEnumerator<KeyValuePair<TKey, T>> GetEnumerator()
{
return CreateEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
So in your case you could derive:
class DaysOfWeekToStringsMap:EnumIndexedArray<DayOfWeek,string>{};
Usage:
var map = new DaysOfWeekToStringsMap();
//using the Keys static property
foreach(var day in DaysOfWeekToStringsMap.Keys){
map[day] = day.ToString();
}
foreach(var day in DaysOfWeekToStringsMap.Keys){
Console.WriteLine("map[{0}]={1}",day, map[day]);
}
// using iterator
foreach(var value in map){
Console.WriteLine("map[{0}]={1}",value.Key, value.Value);
}
Obviously this implementation is backed by an array, so non-contiguous enums like this:
enum
{
Ok = 1,
NotOk = 1000000
}
would result in excessive memory usage.
If you require maximum possible performance you might want to make it less generic and loose all generic enum handling code I had to use to get it to compile and work. I didn't benchmark this though, so maybe it's no big deal.
Caching the Keys static property might also help.
I realize this is an old question, but there have been a number of comments about the fact that all solutions so far have run-time checks to ensure the data type is an enum. Here is a complete solution (with some examples) of a solution with compile time checks (as well as some comments and discussions from my fellow developers)
//There is no good way to constrain a generic class parameter to an Enum. The hack below does work at compile time,
// though it is convoluted. For examples of how to use the two classes EnumIndexedArray and ObjEnumIndexedArray,
// see AssetClassArray below. Or, e.g.
// EConstraint.EnumIndexedArray<int, YourEnum> x = new EConstraint.EnumIndexedArray<int, YourEnum>();
// See this post
// http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum/29581813#29581813
// and the answer/comments by Julien Lebosquain
public class EConstraint : HackForCompileTimeConstraintOfTEnumToAnEnum<System.Enum> { }//THIS MUST BE THE ONLY IMPLEMENTATION OF THE ABSTRACT HackForCompileTimeConstraintOfTEnumToAnEnum
public abstract class HackForCompileTimeConstraintOfTEnumToAnEnum<SystemEnum> where SystemEnum : class
{
//For object types T, users should use EnumIndexedObjectArray below.
public class EnumIndexedArray<T, TEnum>
where TEnum : struct, SystemEnum
{
//Needs to be public so that we can easily do things like intIndexedArray.data.sum()
// - just not worth writing up all the equivalent methods, and we can't inherit from T[] and guarantee proper initialization.
//Also, note that we cannot use Length here for initialization, even if Length were defined the same as GetNumEnums up to
// static qualification, because we cannot use a non-static for initialization here.
// Since we want Length to be non-static, in keeping with other definitions of the Length property, we define the separate static
// GetNumEnums, and then define the non-static Length in terms of the actual size of the data array, just for clarity,
// safety and certainty (in case someone does something stupid like resizing data).
public T[] data = new T[GetNumEnums()];
//First, a couple of statics allowing easy use of the enums themselves.
public static TEnum[] GetEnums()
{
return (TEnum[])Enum.GetValues(typeof(TEnum));
}
public TEnum[] getEnums()
{
return GetEnums();
}
//Provide a static method of getting the number of enums. The Length property also returns this, but it is not static and cannot be use in many circumstances.
public static int GetNumEnums()
{
return GetEnums().Length;
}
//This should always return the same as GetNumEnums, but is not static and does it in a way that guarantees consistency with the member array.
public int Length { get { return data.Length; } }
//public int Count { get { return data.Length; } }
public EnumIndexedArray() { }
// [WDS 2015-04-17] Remove. This can be dangerous. Just force people to use EnumIndexedArray(T[] inputArray).
// [DIM 2015-04-18] Actually, if you think about it, EnumIndexedArray(T[] inputArray) is just as dangerous:
// For value types, both are fine. For object types, the latter causes each object in the input array to be referenced twice,
// while the former causes the single object t to be multiply referenced. Two references to each of many is no less dangerous
// than 3 or more references to one. So all of these are dangerous for object types.
// We could remove all these ctors from this base class, and create a separate
// EnumIndexedValueArray<T, TEnum> : EnumIndexedArray<T, TEnum> where T: struct ...
// but then specializing to TEnum = AssetClass would have to be done twice below, once for value types and once
// for object types, with a repetition of all the property definitions. Violating the DRY principle that much
// just to protect against stupid usage, clearly documented as dangerous, is not worth it IMHO.
public EnumIndexedArray(T t)
{
int i = Length;
while (--i >= 0)
{
this[i] = t;
}
}
public EnumIndexedArray(T[] inputArray)
{
if (inputArray.Length > Length)
{
throw new Exception(string.Format("Length of enum-indexed array ({0}) to big. Can't be more than {1}.", inputArray.Length, Length));
}
Array.Copy(inputArray, data, inputArray.Length);
}
public EnumIndexedArray(EnumIndexedArray<T, TEnum> inputArray)
{
Array.Copy(inputArray.data, data, data.Length);
}
//Clean data access
public T this[int ac] { get { return data[ac]; } set { data[ac] = value; } }
public T this[TEnum ac] { get { return data[Convert.ToInt32(ac)]; } set { data[Convert.ToInt32(ac)] = value; } }
}
public class EnumIndexedObjectArray<T, TEnum> : EnumIndexedArray<T, TEnum>
where TEnum : struct, SystemEnum
where T : new()
{
public EnumIndexedObjectArray(bool doInitializeWithNewObjects = true)
{
if (doInitializeWithNewObjects)
{
for (int i = Length; i > 0; this[--i] = new T()) ;
}
}
// The other ctor's are dangerous for object arrays
}
public class EnumIndexedArrayComparator<T, TEnum> : EqualityComparer<EnumIndexedArray<T, TEnum>>
where TEnum : struct, SystemEnum
{
private readonly EqualityComparer<T> elementComparer = EqualityComparer<T>.Default;
public override bool Equals(EnumIndexedArray<T, TEnum> lhs, EnumIndexedArray<T, TEnum> rhs)
{
if (lhs == rhs)
return true;
if (lhs == null || rhs == null)
return false;
//These cases should not be possible because of the way these classes are constructed.
// HOWEVER, the data member is public, so somebody _could_ do something stupid and make
// data=null, or make lhs.data == rhs.data, even though lhs!=rhs (above check)
//On the other hand, these are just optimizations, so it won't be an issue if we reomve them anyway,
// Unless someone does something really dumb like setting .data to null or resizing to an incorrect size,
// in which case things will crash, but any developer who does this deserves to have it crash painfully...
//if (lhs.data == rhs.data)
// return true;
//if (lhs.data == null || rhs.data == null)
// return false;
int i = lhs.Length;
//if (rhs.Length != i)
// return false;
while (--i >= 0)
{
if (!elementComparer.Equals(lhs[i], rhs[i]))
return false;
}
return true;
}
public override int GetHashCode(EnumIndexedArray<T, TEnum> enumIndexedArray)
{
//This doesn't work: for two arrays ar1 and ar2, ar1.GetHashCode() != ar2.GetHashCode() even when ar1[i]==ar2[i] for all i (unless of course they are the exact same array object)
//return engineArray.GetHashCode();
//Code taken from comment by Jon Skeet - of course - in http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
//31 and 17 are used commonly elsewhere, but maybe because everyone is using Skeet's post.
//On the other hand, this is really not very critical.
unchecked
{
int hash = 17;
int i = enumIndexedArray.Length;
while (--i >= 0)
{
hash = hash * 31 + elementComparer.GetHashCode(enumIndexedArray[i]);
}
return hash;
}
}
}
}
//Because of the above hack, this fails at compile time - as it should. It would, otherwise, only fail at run time.
//public class ThisShouldNotCompile : EConstraint.EnumIndexedArray<int, bool>
//{
//}
//An example
public enum AssetClass { Ir, FxFwd, Cm, Eq, FxOpt, Cr };
public class AssetClassArrayComparator<T> : EConstraint.EnumIndexedArrayComparator<T, AssetClass> { }
public class AssetClassIndexedArray<T> : EConstraint.EnumIndexedArray<T, AssetClass>
{
public AssetClassIndexedArray()
{
}
public AssetClassIndexedArray(T t) : base(t)
{
}
public AssetClassIndexedArray(T[] inputArray) : base(inputArray)
{
}
public AssetClassIndexedArray(EConstraint.EnumIndexedArray<T, AssetClass> inputArray) : base(inputArray)
{
}
public T Cm { get { return this[AssetClass.Cm ]; } set { this[AssetClass.Cm ] = value; } }
public T FxFwd { get { return this[AssetClass.FxFwd]; } set { this[AssetClass.FxFwd] = value; } }
public T Ir { get { return this[AssetClass.Ir ]; } set { this[AssetClass.Ir ] = value; } }
public T Eq { get { return this[AssetClass.Eq ]; } set { this[AssetClass.Eq ] = value; } }
public T FxOpt { get { return this[AssetClass.FxOpt]; } set { this[AssetClass.FxOpt] = value; } }
public T Cr { get { return this[AssetClass.Cr ]; } set { this[AssetClass.Cr ] = value; } }
}
//Inherit from AssetClassArray<T>, not EnumIndexedObjectArray<T, AssetClass>, so we get the benefit of the public access getters and setters above
public class AssetClassIndexedObjectArray<T> : AssetClassIndexedArray<T> where T : new()
{
public AssetClassIndexedObjectArray(bool bInitializeWithNewObjects = true)
{
if (bInitializeWithNewObjects)
{
for (int i = Length; i > 0; this[--i] = new T()) ;
}
}
}
EDIT:
If you are using C# 7.3 or later, PLEASE don't use this ugly solution. See Ian Goldby's answer from 2018.
You can always do some extra mapping to get an array index of an enum value in a consistent and defined way:
int ArrayIndexFromDaysOfTheWeekEnum(DaysOfWeek day)
{
switch (day)
{
case DaysOfWeek.Sunday: return 0;
case DaysOfWeek.Monday: return 1;
...
default: throw ...;
}
}
Be as specific as you can. One day someone will modify your enum and the code will fail because the enum's value was (mis)used as an array index.
For future reference the above problem can be summarized as follows:
I come from Delphi where you can define an array as follows:
type
{$SCOPEDENUMS ON}
TDaysOfTheWeek = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
TDaysOfTheWeekStrings = array[TDaysOfTheWeek];
Then you can iterate through the array using Min and Max:
for Dow := Min(TDaysOfTheWeek) to Max(TDaysOfTheWeek)
DaysOfTheWeekStrings[Dow] := '';
Though this is quite a contrived example, when you are dealing with array positions later in the code I can just type DaysOfTheWeekStrings[TDaysOfTheWeek.Monday]. This has the advantage of the fact that I should the TDaysOfTheWeek increase in size then I do not have to remember the new size of the array etc..... However back to the C# world. I have found this example C# Enum Array Example.
It was a very good answer by #ian-goldby, but it didn't address the issue raised by #zar-shardan, which is an issue I hit myself. Below is my take on a solution, with a an extension class for converting an IEnumerable, and a test class below that:
/// <summary>
/// An array indexed by an enumerated type instead of an integer
/// </summary>
public class ArrayIndexedByEnum<TKey, TElement> : IEnumerable<TElement> where TKey : Enum
{
private readonly Array _array;
private readonly Dictionary<TKey, TElement> _dictionary;
/// <summary>
/// Creates the initial array, populated with the defaults for TElement
/// </summary>
public ArrayIndexedByEnum()
{
var min = Convert.ToInt64(Enum.GetValues(typeof(TKey)).Cast<TKey>().Min());
var max = Convert.ToInt64(Enum.GetValues(typeof(TKey)).Cast<TKey>().Max());
var size = max - min + 1;
// Check that we aren't creating a ridiculously big array, if we are,
// then use a dictionary instead
if (min >= Int32.MinValue &&
max <= Int32.MaxValue &&
size < Enum.GetValues(typeof(TKey)).Length * 3L)
{
var lowerBound = Convert.ToInt32(min);
var upperBound = Convert.ToInt32(max);
_array = Array.CreateInstance(typeof(TElement), new int[] {(int)size }, new int[] { lowerBound });
}
else
{
_dictionary = new Dictionary<TKey, TElement>();
foreach (var value in Enum.GetValues(typeof(TKey)).Cast<TKey>())
{
_dictionary[value] = default(TElement);
}
}
}
/// <summary>
/// Gets the element by enumerated type
/// </summary>
public TElement this[TKey key]
{
get => (TElement)(_array?.GetValue(Convert.ToInt32(key)) ?? _dictionary[key]);
set
{
if (_array != null)
{
_array.SetValue(value, Convert.ToInt32(key));
}
else
{
_dictionary[key] = value;
}
}
}
/// <summary>
/// Gets a generic enumerator
/// </summary>
public IEnumerator<TElement> GetEnumerator()
{
return Enum.GetValues(typeof(TKey)).Cast<TKey>().Select(k => this[k]).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Here's the extension class:
/// <summary>
/// Extensions for converting IEnumerable<TElement> to ArrayIndexedByEnum
/// </summary>
public static class ArrayIndexedByEnumExtensions
{
/// <summary>
/// Creates a ArrayIndexedByEnumExtensions from an System.Collections.Generic.IEnumerable
/// according to specified key selector and element selector functions.
/// </summary>
public static ArrayIndexedByEnum<TKey, TElement> ToArrayIndexedByEnum<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) where TKey : Enum
{
var array = new ArrayIndexedByEnum<TKey, TElement>();
foreach(var item in source)
{
array[keySelector(item)] = elementSelector(item);
}
return array;
}
/// <summary>
/// Creates a ArrayIndexedByEnum from an System.Collections.Generic.IEnumerable
/// according to a specified key selector function.
/// </summary>
public static ArrayIndexedByEnum<TKey, TSource> ToArrayIndexedByEnum<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) where TKey : Enum
{
return source.ToArrayIndexedByEnum(keySelector, i => i);
}
}
And here are my tests:
[TestClass]
public class ArrayIndexedByEnumUnitTest
{
private enum OddNumbersEnum : UInt16
{
One = 1,
Three = 3,
Five = 5,
Seven = 7,
Nine = 9
}
private enum PowersOf2 : Int64
{
TwoP0 = 1,
TwoP1 = 2,
TwoP2 = 4,
TwoP3 = 8,
TwoP4 = 16,
TwoP5 = 32,
TwoP6 = 64,
TwoP7 = 128,
TwoP8 = 256,
TwoP9 = 512,
TwoP10 = 1_024,
TwoP11 = 2_048,
TwoP12 = 4_096,
TwoP13 = 8_192,
TwoP14 = 16_384,
TwoP15 = 32_768,
TwoP16 = 65_536,
TwoP17 = 131_072,
TwoP18 = 262_144,
TwoP19 = 524_288,
TwoP20 = 1_048_576,
TwoP21 = 2_097_152,
TwoP22 = 4_194_304,
TwoP23 = 8_388_608,
TwoP24 = 16_777_216,
TwoP25 = 33_554_432,
TwoP26 = 67_108_864,
TwoP27 = 134_217_728,
TwoP28 = 268_435_456,
TwoP29 = 536_870_912,
TwoP30 = 1_073_741_824,
TwoP31 = 2_147_483_648,
TwoP32 = 4_294_967_296,
TwoP33 = 8_589_934_592,
TwoP34 = 17_179_869_184,
TwoP35 = 34_359_738_368,
TwoP36 = 68_719_476_736,
TwoP37 = 137_438_953_472,
TwoP38 = 274_877_906_944,
TwoP39 = 549_755_813_888,
TwoP40 = 1_099_511_627_776,
TwoP41 = 2_199_023_255_552,
TwoP42 = 4_398_046_511_104,
TwoP43 = 8_796_093_022_208,
TwoP44 = 17_592_186_044_416,
TwoP45 = 35_184_372_088_832,
TwoP46 = 70_368_744_177_664,
TwoP47 = 140_737_488_355_328,
TwoP48 = 281_474_976_710_656,
TwoP49 = 562_949_953_421_312,
TwoP50 = 1_125_899_906_842_620,
TwoP51 = 2_251_799_813_685_250,
TwoP52 = 4_503_599_627_370_500,
TwoP53 = 9_007_199_254_740_990,
TwoP54 = 18_014_398_509_482_000,
TwoP55 = 36_028_797_018_964_000,
TwoP56 = 72_057_594_037_927_900,
TwoP57 = 144_115_188_075_856_000,
TwoP58 = 288_230_376_151_712_000,
TwoP59 = 576_460_752_303_423_000,
TwoP60 = 1_152_921_504_606_850_000,
}
[TestMethod]
public void TestSimpleArray()
{
var array = new ArrayIndexedByEnum<OddNumbersEnum, string>();
var odds = Enum.GetValues(typeof(OddNumbersEnum)).Cast<OddNumbersEnum>().ToList();
// Store all the values
foreach (var odd in odds)
{
array[odd] = odd.ToString();
}
// Check the retrieved values are the same as what was stored
foreach (var odd in odds)
{
Assert.AreEqual(odd.ToString(), array[odd]);
}
}
[TestMethod]
public void TestPossiblyHugeArray()
{
var array = new ArrayIndexedByEnum<PowersOf2, string>();
var powersOf2s = Enum.GetValues(typeof(PowersOf2)).Cast<PowersOf2>().ToList();
// Store all the values
foreach (var powerOf2 in powersOf2s)
{
array[powerOf2] = powerOf2.ToString();
}
// Check the retrieved values are the same as what was stored
foreach (var powerOf2 in powersOf2s)
{
Assert.AreEqual(powerOf2.ToString(), array[powerOf2]);
}
}
}
Related
I'm implementing a custom data store against an in memory state tree and I'm running into some issues with my indexing. My indexes are meant to be covering, so they should return the object not just a position. An index has a name, and a List of objects. Those objects can be different underlying types so the indexed objects are IHasUUID which indicates an item has a UUID.
public class DataIndex
{
public string Name;
public IDictionary<string, List<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
...
public List<IHasUUID> GetIndexedItems(List<IHasUUID> indexBy)
{
var indexer = GetIndexByKeys<IHasUUID>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUUID>(indexer, indexHash);
}
private List<T> GetIndexValues<T>(DataIndex indexBy, string indexHash) where T : IHasUUID
{
if (indexBy == null)
return new List<T>();
return ((IList<T>)indexBy.Index[indexHash]).ToList();
}
}
I generate the key to the dictionary using a reflection method where I look at the things being used as the index key and append the type string names
So I ask my Engine to FindRecords, no problem
public List<T> FindRecords<T>(IHasUUID indexBy) where T : IHasUUID
{
var indexedIds = Indexer.GetIndexedItems(new List<IHasUUID>() { indexBy });
return ((IList<T>)indexedIds).ToList();
}
Here I run into a wall on the FindRecords return
I have
return ((IList<T>)indexedIds).ToList();
and I tried
return indexedIds.ToList();
Neither one is able to cast up to T. Is this possible?
Thanks in advance
EDIT
I do seem to be much closer,
public class DataIndex
{
public DataIndex()
{
Index = new Dictionary<string, IEnumerable<IHasUUID>>();
}
public string Name;
public Dictionary<string, IEnumerable<IHasUUID>> Index;
}
public class Indexer
{
private List<DataIndex> Indexes;
public Indexer()
{
Indexes = new List<DataIndex>();
}
public IEnumerable<T> GetIndexedItems<T>(IEnumerable<IHasUUID> indexBy) where T : IHasUUID
{
var indexer = GetIndexByKeys<T>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<T>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string indexHash) where T : IHasUUID
{
if (dataIndex == null)
return new List<T>();
return dataIndex.Index[indexHash].ToList() as List<T>;
}
}
However I am getting null back from GetIndexValues. I also tried returning it as an IEnumerable, also null
Here's my Add to index method
public void AddManyToIndex<T>(IEnumerable<IHasUUID> keys, IEnumerable<IHasUUID> newItems) where T : IHasUUID
{
var index = GetIndexByKeys<T>(keys) ?? CreateIndex<T>(keys);
string indexKey = GetHashKey(keys);
if (!index.Index.ContainsKey(indexKey))
{
index.Index[indexKey] = new List<IHasUUID>();
}
var list = index.Index[indexKey].ToList();
list.AddRange(newItems.ToList());
index.Index[indexKey] = list as IEnumerable<IHasUUID>;
}
System.Collections.Generic.List<T> is not covariant. That is to say that, given two types T and U where a U is a T, a List<U> is not a List<T>.
This is why the cast fails, a list of a type implementing IHasUUID, T in your example, is not a List<IHasUUID>.
There are however, covariant1 generic types, such as System.Collections.Generic.IEnumerable<T> and System.Collections.Generic.IReadOnlyList<T>. For such types, given two types T and U where a U is a T, an IEnumerable<U> is an IEnumerable<T>.
In addition to solving your specific problem, using such types will also serve to make your APIs more flexible while at the same time making your implementation simpler and easier.
Consider the following:
public interface IHasUuid
{
Guid Uuid { get; }
}
public class DataIndex
{
public string Name { get; set; }
public IDictionary<string, IEnumerable<IHasUuid>> Index { get; } = new Dictionary<string, IEnumerable<IHasUuid>>();
}
public class Indexer
{
public IEnumerable<IHasUuid> GetIndexedItems(IEnumerable<IHasUuid> indexBy)
{
var indexer = GetIndexByKeys<IHasUuid>(indexBy);
var indexHash = GetHashKey(indexBy);
return GetIndexValues<IHasUuid>(indexer, indexHash);
}
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return dataIndex.Index[hash] as IEnumerable<T>;
}
}
You can store any type that implements IEnumerable<IHasUuid> in DataIndex.Index. All generic collections in .NET implement this interface, including List<T>, HashSet<T>, ConcurrentQueue<T> and countless more.
If you wish to retain the defensive copying in the orginal code, which may well be wise, simply add the .ToWhatever() back to the code.
private IEnumerable<T> GetIndexValues<T>(DataIndex dataIndex, string hash) where T : IHasUuid
{
if (dataIndex == null)
return Enumerable.Empty<T>();
return (dataIndex.Index[hash] as IEnumerable<T>).ToHashSet();
}
For example, you can build up a DataIndex instance like this
class Person: IHasUuid {
public Guid Uuid { get; }
public string Name { get; }
}
var index = new DataIndex {
Index = {
["People"] = new List<Person>()
}
};
var indexer = new Indexer();
var people = indexer.GetIndexValues(index, "People");
Here's a working fiddle: https://dotnetfiddle.net/qgjXR7
1: A type is covariant over its type parameter if that type parameter is declared using the out modifier. As its name suggests, the out modifier means that type parameter to which it is ascribed may only be used in output positions in the declaring type.
interface Wrapper<out T>
{
T Value { get; } // OK
T Value { get; set; } // Error
void SetValue(T value); // Error
}
Interface and delegate types can declare covariant type parameters, concrete types such as classes and structs may not.
I have a class called GenericItem (first time using generics), suppose i wanted to multiply two items if they were of the type integer, as you can see I am trying it in the method returnCounterMultiply, but it does not allow me to multiply them although i am trying to convert them and also checking if they are of type integer.
namespace Components
{
public class GenericItem<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
int c = 0;
int d = 0;
if (counter.GetType() == typeof(int) && value.GetType() == typeof(int))
{
//cant multiply two of type T, why if i am converting to int?.
return (T)Convert.ChangeType(counter, typeof(Int32)) * (T)Convert.ChangeType(value, typeof(Int32));
}
return value;
}
}
}
I would appreciate some explanation on this as this is the first time I am working on it (this is just a sample class for understanding this GENERICS INTRO and this GENERICS CLASSES, but still having trouble understanding it.
I don't see what your trying to achieve, but if you have to do it I think you have to use an interface:
public interface IMultiplyable<T>
{
T Multiply(T x);
}
public class Int : IMultiplyable<Int>
{
private int _data { get; set; }
public Int(int data)
{
_data = data;
}
public Int Multiply(Int x)
{
return new Int(_data * x._data);
}
public override string ToString()
{
return _data.ToString();
}
}
public class GenericItem<T> where T : IMultiplyable<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem() { }
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
return Data.Multiply(value);
}
public override string ToString()
{
return Data.ToString();
}
}
Usage:
var a = new GenericItem<Int>(new Int(4));
MessageBox.Show(a.returnCounterMultiply(new Int(5)).ToString()); //20
In my opinion, using generics in this case is an overkill.
It would be nice that generic constraints support something like:
// T parameter is a type which overloads "+" operator...
where T : +
In your concrete case, I would argue you're going in the wrong way. Why don't you just create a class to implement such math operations where properties are typed as int?
Generics work better when T parameter (or any other parameter, of course...) can be constrained to receive types which have:
A public parameterless constructor.
Inherits or implements a class/interface
You need to constraint that T must be a class and not a struct...
When you go into a problem when using generics requires a type conversion, I believe you defeated the point of generics!
You can do something like this:
public class GenericItem<T>
{
private T data;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
private Dictionary<Type, Delegate> operations =
new Dictionary<Type, Delegate>()
{
{ typeof(int), (Func<int, int, int>)((x, y) => x * y) },
{ typeof(string), (Func<string, string, string>)((x, y) => x + " " + y) },
};
public T returnCounterMultiply(T value)
{
if (operations.ContainsKey(typeof(T)))
{
var operation = (Func<T, T, T>)(operations[typeof(T)]);
return operation(data, value);
}
return value;
}
}
You just need to define, in the dictionary, one operation per valid types you're going to want to use and it just works without any converting of types (except to cast to the Func).
I had these test results:
var gii = new GenericItem<int>(42);
var xi = gii.returnCounterMultiply(2);
// xi == 84
var gis = new GenericItem<string>("Foo");
var xs = gis.returnCounterMultiply("Bar");
// xs == "Foo Bar"
Your problem has nothing to do with generics but with basic C# casting priority:
//cant multiply two of type T, why if i am converting to int?.
return
(T)Convert.ChangeType(counter, typeof(Int32))
*
(T)Convert.ChangeType(value,typeof(Int32));
You do not multiply int but T - and T being a generic type you can only use methods that are ddefined in your generics contraint, which you have none, so no multiply on it.
If you want to multiply int, then do so:
(T) (
((Int32)Convert.ChangeType(counter, typeof(Int32)))
*
((Int32)Convert.ChangeType(value,typeof(Int32)))
);
See the difference?
Basically in your code you deal with T in the multiplication, here I deal with Int32. And factually if T is a Int32 (as you tested before in the IF statement) you can just skip the convert and cast:
(T) (
((Int32)counter)
*
((Int32)value)
);
Now, generics are a bad example for maths as you can not use operations on generics - sadly. This is an abuse of the concept, but I take it was meant as a learning exercise and thus focused on that part on my answer.
I too tried this once and had to find out that there is no pretty way to do it with generics. You cannot do it as generic as in C++.
As an alternative, you may wrap your data types and use a common interface:
interface IMathOps
{
object Value { get; }
void Add(IMathOps other);
// other methods for substraction etc.
}
class IntWrapper : IMathOps
{
public int value;
public void Add(IMathOps other)
{
if(other is IntWrapper)
{
this.value += (int)other.Value;
}
}
public object Value { get { return this.value; } }
}
// class FloatWrapper : IMathOps ...
I think you should use where (generic type constraint). So it will give error at compile time if T is not int.
public T returnCounterMultiply(T value) where T : int
{
int c = 0;
int d = 0;
return c*d;
}
Is there a well-known way for simulating the variadic template feature in C#?
For instance, I'd like to write a method that takes a lambda with an arbitrary set of parameters. Here is in pseudo code what I'd like to have:
void MyMethod<T1,T2,...,TReturn>(Fun<T1,T2, ..., TReturn> f)
{
}
C# generics are not the same as C++ templates. C++ templates are expanded compiletime and can be used recursively with variadic template arguments. The C++ template expansion is actually Turing Complete, so there is no theoretically limit to what can be done in templates.
C# generics are compiled directly, with an empty "placeholder" for the type that will be used at runtime.
To accept a lambda taking any number of arguments you would either have to generate a lot of overloads (through a code generator) or accept a LambdaExpression.
There is no varadic support for generic type arguments (on either methods or types). You will have to add lots of overloads.
varadic support is only available for arrays, via params, i.e.
void Foo(string key, params int[] values) {...}
Improtantly - how would you even refer to those various T* to write a generic method? Perhaps your best option is to take a Type[] or similar (depending on the context).
I know this is an old question, but if all you want to do is something simple like print those types out, you can do this very easily without Tuple or anything extra using 'dynamic':
private static void PrintTypes(params dynamic[] args)
{
foreach (var arg in args)
{
Console.WriteLine(arg.GetType());
}
}
static void Main(string[] args)
{
PrintTypes(1,1.0,"hello");
Console.ReadKey();
}
Will print "System.Int32" , "System.Double", "System.String"
If you want to perform some action on these things, as far as I know you have two choices. One is to trust the programmer that these types can do a compatible action, for example if you wanted to make a method to Sum any number of parameters. You could write a method like the following saying how you want to receive the result and the only prerequisite I guess would be that the + operation works between these types:
private static void AddToFirst<T>(ref T first, params dynamic[] args)
{
foreach (var arg in args)
{
first += arg;
}
}
static void Main(string[] args)
{
int x = 0;
AddToFirst(ref x,1,1.5,2.0,3.5,2);
Console.WriteLine(x);
double y = 0;
AddToFirst(ref y, 1, 1.5, 2.0, 3.5, 2);
Console.WriteLine(y);
Console.ReadKey();
}
With this, the output for the first line would be "9" because adding to an int, and the second line would be "10" because the .5s didn't get rounded, adding as a double. The problem with this code is if you pass some incompatible type in the list, it will have an error because the types can't get added together, and you won't see that error at compile time, only at runtime.
So, depending on your use case there might be another option which is why I said there were two choices at first. Assuming you know the choices for the possible types, you could make an interface or abstract class and make all of those types implement the interface. For example, the following. Sorry this is a bit crazy. And it can probably be simplfied.
public interface Applyable<T>
{
void Apply(T input);
T GetValue();
}
public abstract class Convertable<T>
{
public dynamic value { get; set; }
public Convertable(dynamic value)
{
this.value = value;
}
public abstract T GetConvertedValue();
}
public class IntableInt : Convertable<int>, Applyable<int>
{
public IntableInt(int value) : base(value) {}
public override int GetConvertedValue()
{
return value;
}
public void Apply(int input)
{
value += input;
}
public int GetValue()
{
return value;
}
}
public class IntableDouble : Convertable<int>
{
public IntableDouble(double value) : base(value) {}
public override int GetConvertedValue()
{
return (int) value;
}
}
public class IntableString : Convertable<int>
{
public IntableString(string value) : base(value) {}
public override int GetConvertedValue()
{
// If it can't be parsed return zero
int result;
return int.TryParse(value, out result) ? result : 0;
}
}
private static void ApplyToFirst<TResult>(ref Applyable<TResult> first, params Convertable<TResult>[] args)
{
foreach (var arg in args)
{
first.Apply(arg.GetConvertedValue());
}
}
static void Main(string[] args)
{
Applyable<int> result = new IntableInt(0);
IntableInt myInt = new IntableInt(1);
IntableDouble myDouble1 = new IntableDouble(1.5);
IntableDouble myDouble2 = new IntableDouble(2.0);
IntableDouble myDouble3 = new IntableDouble(3.5);
IntableString myString = new IntableString("2");
ApplyToFirst(ref result, myInt, myDouble1, myDouble2, myDouble3, myString);
Console.WriteLine(result.GetValue());
Console.ReadKey();
}
Will output "9" the same as the original Int code, except the only values you can actually pass in as parameters are things that you actually have defined and you know will work and not cause any errors. Of course, you would have to make new classes i.e. DoubleableInt , DoubleableString, etc.. in order to re-create the 2nd result of 10. But this is just an example, so you wouldn't even be trying to add things at all depending on what code you are writing and you would just start out with the implementation that served you the best.
Hopefully someone can improve on what I wrote here or use it to see how this can be done in C#.
Another alternative besides those mentioned above is to use Tuple<,> and reflection, for example:
class PrintVariadic<T>
{
public T Value { get; set; }
public void Print()
{
InnerPrint(Value);
}
static void InnerPrint<Tn>(Tn t)
{
var type = t.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Tuple<,>))
{
var i1 = type.GetProperty("Item1").GetValue(t, new object[]{});
var i2 = type.GetProperty("Item2").GetValue(t, new object[]{ });
InnerPrint(i1);
InnerPrint(i2);
return;
}
Console.WriteLine(t.GetType());
}
}
class Program
{
static void Main(string[] args)
{
var v = new PrintVariadic<Tuple<
int, Tuple<
string, Tuple<
double,
long>>>>();
v.Value = Tuple.Create(
1, Tuple.Create(
"s", Tuple.Create(
4.0,
4L)));
v.Print();
Console.ReadKey();
}
}
I don't necessarily know if there's a name for this pattern, but I arrived at the following formulation for a recursive generic interface that allows an unlimited amount of values to be passed in, with the returned type retaining type information for all passed values.
public interface ITraversalRoot<TRoot>
{
ITraversalSpecification<TRoot> Specify();
}
public interface ITraverser<TRoot, TCurrent>: ITraversalRoot<TRoot>
{
IDerivedTraverser<TRoot, TInclude, TCurrent, ITraverser<TRoot, TCurrent>> AndInclude<TInclude>(Expression<Func<TCurrent, TInclude>> path);
}
public interface IDerivedTraverser<TRoot, TDerived, TParent, out TParentTraverser> : ITraverser<TRoot, TParent>
{
IDerivedTraverser<TRoot, TInclude, TDerived, IDerivedTraverser<TRoot, TDerived, TParent, TParentTraverser>> FromWhichInclude<TInclude>(Expression<Func<TDerived, TInclude>> path);
TParentTraverser ThenBackToParent();
}
There's no casting or "cheating" of the type system involved here: you can keep stacking on more values and the inferred return type keeps storing more and more information. Here is what the usage looks like:
var spec = Traversal
.StartFrom<VirtualMachine>() // ITraverser<VirtualMachine, VirtualMachine>
.AndInclude(vm => vm.EnvironmentBrowser) // IDerivedTraverser<VirtualMachine, EnvironmentBrowser, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.AndInclude(vm => vm.Datastore) // IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.FromWhichInclude(ds => ds.Browser) // IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>
.FromWhichInclude(br => br.Mountpoints) // IDerivedTraverser<VirtualMachine, Mountpoint, HostDatastoreBrowser, IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>>
.Specify(); // ITraversalSpecification<VirtualMachine>
As you can see the type signature becomes basically unreadable near after a few chained calls, but this is fine so long as type inference works and suggests the right type to the user.
In my example I am dealing with Funcs arguments, but you could presumably adapt this code to deal with arguments of arbitrary type.
For a simulation you can say:
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
where Tparams to be a variadic arguments implementation class. However, the framework does not provide an out-of-box stuff to do that, Action, Func, Tuple, etc., are all have limited length of their signatures. The only thing I can think of is to apply the CRTP .. in a way I've not find somebody blogged. Here's my implementation:
*: Thank #SLaks for mentioning Tuple<T1, ..., T7, TRest> also works in a recursive way. I noticed it's recursive on the constructor and the factory method instead of its class definition; and do a runtime type checking of the last argument of type TRest is required to be a ITupleInternal; and this works a bit differently.
Code
using System;
namespace VariadicGenerics {
public interface INode {
INode Next {
get;
}
}
public interface INode<R>:INode {
R Value {
get; set;
}
}
public abstract class Tparams {
public static C<TValue> V<TValue>(TValue x) {
return new T<TValue>(x);
}
}
public class T<P>:C<P> {
public T(P x) : base(x) {
}
}
public abstract class C<R>:Tparams, INode<R> {
public class T<P>:C<T<P>>, INode<P> {
public T(C<R> node, P x) {
if(node is R) {
Next=(R)(node as object);
}
else {
Next=(node as INode<R>).Value;
}
Value=x;
}
public T() {
if(Extensions.TypeIs(typeof(R), typeof(C<>.T<>))) {
Next=(R)Activator.CreateInstance(typeof(R));
}
}
public R Next {
private set;
get;
}
public P Value {
get; set;
}
INode INode.Next {
get {
return this.Next as INode;
}
}
}
public new T<TValue> V<TValue>(TValue x) {
return new T<TValue>(this, x);
}
public int GetLength() {
return m_expandedArguments.Length;
}
public C(R x) {
(this as INode<R>).Value=x;
}
C() {
}
static C() {
m_expandedArguments=Extensions.GetExpandedGenericArguments(typeof(R));
}
// demonstration of non-recursive traversal
public INode this[int index] {
get {
var count = m_expandedArguments.Length;
for(INode node = this; null!=node; node=node.Next) {
if(--count==index) {
return node;
}
}
throw new ArgumentOutOfRangeException("index");
}
}
R INode<R>.Value {
get; set;
}
INode INode.Next {
get {
return null;
}
}
static readonly Type[] m_expandedArguments;
}
}
Note the type parameter for the inherited class C<> in the declaration of
public class T<P>:C<T<P>>, INode<P> {
is T<P>, and the class T<P> is nested so that you can do some crazy things such as:
Test
[Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
public class TestClass {
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>
crazy = Tparams
// trying to change any value to not match the
// declaring type makes the compilation fail
.V((byte)1).V('2').V(4u).V(8L)
.V((byte)1).V('2').V(8L).V(4u)
.V((byte)1).V(8L).V('2').V(4u)
.V(8L).V((byte)1).V('2').V(4u)
.V(8L).V((byte)1).V(4u).V('2')
.V((byte)1).V(8L).V(4u).V('2')
.V((byte)1).V(4u).V(8L).V('2')
.V((byte)1).V(4u).V('2').V(8L)
.V(4u).V((byte)1).V('2').V(8L)
.V(4u).V((byte)1).V(8L).V('2')
.V(4u).V(8L).V((byte)1).V('2')
.V(8L).V(4u).V((byte)1).V('2')
.V(8L).V(4u).V('9').V((byte)1)
.V(4u).V(8L).V('2').V((byte)1)
.V(4u).V('2').V(8L).V((byte)1)
.V(4u).V('2').V((byte)1).V(8L)
.V('2').V(4u).V((byte)1).V(8L)
.V('2').V(4u).V(8L).V((byte)1)
.V('2').V(8L).V(4u).V((byte)1)
.V(8L).V('2').V(4u).V((byte)1)
.V(8L).V('2').V((byte)1).V(4u)
.V('2').V(8L).V((byte)1).V(4u)
.V('2').V((byte)1).V(8L).V(4u)
.V('7').V((byte)1).V(4u).V(8L);
var args = crazy as TSource;
if(null!=args) {
f(args);
}
}
[TestMethod]
public void TestMethod() {
Func<
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>, String>
f = args => {
Debug.WriteLine(String.Format("Length={0}", args.GetLength()));
// print fourth value from the last
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
args.Next.Next.Next.Value='x';
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
return "test";
};
MyMethod(f);
}
}
Another thing to note is we have two classes named T, the non-nested T:
public class T<P>:C<P> {
is just for the consistency of usage, and I made class C abstract to not directly being newed.
The Code part above needs to expand ther generic argument to calculate about their length, here are two extension methods it used:
Code(extensions)
using System.Diagnostics;
using System;
namespace VariadicGenerics {
[DebuggerStepThrough]
public static class Extensions {
public static readonly Type VariadicType = typeof(C<>.T<>);
public static bool TypeIs(this Type x, Type d) {
if(null==d) {
return false;
}
for(var c = x; null!=c; c=c.BaseType) {
var a = c.GetInterfaces();
for(var i = a.Length; i-->=0;) {
var t = i<0 ? c : a[i];
if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
return true;
}
}
}
return false;
}
public static Type[] GetExpandedGenericArguments(this Type t) {
var expanded = new Type[] { };
for(var skip = 1; t.TypeIs(VariadicType) ? true : skip-->0;) {
var args = skip>0 ? t.GetGenericArguments() : new[] { t };
if(args.Length>0) {
var length = args.Length-skip;
var temp = new Type[length+expanded.Length];
Array.Copy(args, skip, temp, 0, length);
Array.Copy(expanded, 0, temp, length, expanded.Length);
expanded=temp;
t=args[0];
}
}
return expanded;
}
}
}
For this implementation, I choosed not to break the compile-time type checking, so we do not have a constructor or a factory with the signature like params object[] to provide values; instead, use a fluent pattern of method V for mass object instantiation to keep type can be statically type checked as much as possible.
class MyGenericClass<T> where T : ICompareable
{
T[] data;
public AddData(T[] values)
{
data = values;
}
}
In my mainForm, I create 3 random numbers, and add them as values: 1 3 3, resulting in:
T[] data : [0]1
[1]3
[2]3
I want to be able to search for a specific value and have the number of times that value is present in the array returned to me.
How do I do that in C#?
return data.Count(t => t.CompareTo(valueToSearchFor) == 0);
This should work for you:
public class MyGenericClass<T> where T : IComparable
{
T[] Data;
public void AddData(T[] values)
{
Data = values;
var list = Data.ToList();
object compareWith = new object();
compareWith = 3;
int count = list.Where(a=>a.CompareTo(compareWith) == 0).Count();
}
}
this can be easily done since you have your type parameter implement IComparable. all you need is this:
internal class MyGenericClass<T> where T : IComparable
{
private T[] data;
public void AddData(T[] values)
{
data = values;
}
public int FindValue<T>(T value)
{
return data.Count(v => v.CompareTo(value) == 0);
}
}
and the call would be something like:
var myClass = new MyGenericClass<int>();
myClass.AddData(new[] {1,2,3,1});
var count = myClass.FindValue(1);
and that should work (worked for me ;) )
Hope this helps :)
I have an object that needs to be serialized to an EDI format. For this example we'll say it's a car. A car might not be the best example b/c options change over time, but for the real object the Enums will never change.
I have many Enums like the following with custom attributes applied.
public enum RoofStyle
{
[DisplayText("Glass Top")]
[StringValue("GTR")]
Glass,
[DisplayText("Convertible Soft Top")]
[StringValue("CST")]
ConvertibleSoft,
[DisplayText("Hard Top")]
[StringValue("HT ")]
HardTop,
[DisplayText("Targa Top")]
[StringValue("TT ")]
Targa,
}
The Attributes are accessed via Extension methods:
public static string GetStringValue(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].StringValue : null;
}
public static string GetDisplayText(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the DisplayText attributes
DisplayTextAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(DisplayTextAttribute), false) as DisplayTextAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].DisplayText : value.ToString();
}
There is a custom EDI serializer that serializes based on the StringValue attributes like so:
StringBuilder sb = new StringBuilder();
sb.Append(car.RoofStyle.GetStringValue());
sb.Append(car.TireSize.GetStringValue());
sb.Append(car.Model.GetStringValue());
...
There is another method that can get Enum Value from StringValue for Deserialization:
car.RoofStyle = Enums.GetCode<RoofStyle>(EDIString.Substring(4, 3))
Defined as:
public static class Enums
{
public static T GetCode<T>(string value)
{
foreach (object o in System.Enum.GetValues(typeof(T)))
{
if (((Enum)o).GetStringValue() == value.ToUpper())
return (T)o;
}
throw new ArgumentException("No code exists for type " + typeof(T).ToString() + " corresponding to value of " + value);
}
}
And Finally, for the UI, the GetDisplayText() is used to show the user friendly text.
What do you think? Overkill? Is there a better way? or Goldie Locks (just right)?
Just want to get feedback before I intergrate it into my personal framework permanently. Thanks.
The part you're using to serialize is fine. The deserialization part is awkwardly written. The main problem is that you're using ToUpper() to compare strings, which is easily broken (think globalization). Such comparisons should be done with string.Compare instead, or the string.Equals overload that takes a StringComparison.
The other thing is that performing these lookups again and again during deserialization is going to pretty slow. If you're serializing a lot of data, this could actually be quite noticeable. In that case, you'd want to build a map from the StringValue to the enum itself - throw it into a static Dictionary<string, RoofStyle> and use it as a lookup for the round-trip. In other words:
public static class Enums
{
private static Dictionary<string, RoofStyle> roofStyles =
new Dictionary<string, RoofStyle>()
{
{ "GTR", RoofStyle.Glass },
{ "CST", RoofStyle.ConvertibleSoft },
{ "HT ", RoofStyle.HardTop },
{ "TT ", RoofStyle.TargaTop }
}
public static RoofStyle GetRoofStyle(string code)
{
RoofStyle result;
if (roofStyles.TryGetValue(code, out result))
return result;
throw new ArgumentException(...);
}
}
It's not as "generic" but it's way more efficient. If you don't like the duplication of string values then extract the codes as constants in a separate class.
If you really need it to be totally generic and work for any enum, you can always lazy-load the dictionary of values (generate it using the extension methods you've written) the first time a conversion is done. It's very simple to do that:
static Dictionary<string, T> CreateEnumLookup<T>()
{
return Enum.GetValues(typeof(T)).ToDictionary(o => ((Enum)o).GetStringValue(),
o => (T)o);
}
P.S. Minor detail but you might want to consider using Attribute.GetCustomAttribute instead of MemberInfo.GetCustomAttributes if you only expect there to be one attribute. There's no reason for all the array fiddling when you only need one item.
Personally, I think you are abusing the language and trying to use enums in a way they were never intended. I would create a static class RoofStyle, and create a simple struct RoofType, and use an instance for each of your enum values.
Why don't you create a type with static members such as mikerobi said
Example...
public class RoofStyle
{
private RoofStyle() { }
public string Display { get; private set; }
public string Value { get; private set; }
public readonly static RoofStyle Glass = new RoofStyle
{
Display = "Glass Top", Value = "GTR",
};
public readonly static RoofStyle ConvertibleSoft = new RoofStyle
{
Display = "Convertible Soft Top", Value = "CST",
};
public readonly static RoofStyle HardTop = new RoofStyle
{
Display = "Hard Top", Value = "HT ",
};
public readonly static RoofStyle Targa = new RoofStyle
{
Display = "Targa Top", Value = "TT ",
};
}
BTW...
When compiled into IL an Enum is very similar to this class structure.
... Enum backing fields ...
.field public specialname rtspecialname int32 value__
.field public static literal valuetype A.ERoofStyle Glass = int32(0x00)
.field public static literal valuetype A.ERoofStyle ConvertibleSoft = int32(0x01)
.field public static literal valuetype A.ERoofStyle HardTop = int32(0x02)
.field public static literal valuetype A.ERoofStyle Targa = int32(0x03)
... Class backing fields ...
.field public static initonly class A.RoofStyle Glass
.field public static initonly class A.RoofStyle ConvertibleSoft
.field public static initonly class A.RoofStyle HardTop
.field public static initonly class A.RoofStyle Targa
Here is a base class I use for enumeration classes:
public abstract class Enumeration<T, TId> : IEquatable<T> where T : Enumeration<T, TId>
{
public static bool operator ==(Enumeration<T, TId> x, T y)
{
return Object.ReferenceEquals(x, y) || (!Object.ReferenceEquals(x, null) && x.Equals(y));
}
public static bool operator !=(Enumeration<T, TId> first, T second)
{
return !(first == second);
}
public static T FromId(TId id)
{
return AllValues.Where(value => value.Id.Equals(id)).FirstOrDefault();
}
public static readonly ReadOnlyCollection<T> AllValues = FindValues();
private static ReadOnlyCollection<T> FindValues()
{
var values =
(from staticField in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public)
where staticField.FieldType == typeof(T)
select (T) staticField.GetValue(null))
.ToList()
.AsReadOnly();
var duplicateIds =
(from value in values
group value by value.Id into valuesById
where valuesById.Skip(1).Any()
select valuesById.Key)
.Take(1)
.ToList();
if(duplicateIds.Count > 0)
{
throw new DuplicateEnumerationIdException("Duplicate ID: " + duplicateIds.Single());
}
return values;
}
protected Enumeration(TId id, string name)
{
Contract.Requires(((object) id) != null);
Contract.Requires(!String.IsNullOrEmpty(name));
this.Id = id;
this.Name = name;
}
protected Enumeration()
{}
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public override string ToString()
{
return this.Name;
}
#region IEquatable
public virtual bool Equals(T other)
{
return other != null && this.IdComparer.Equals(this.Id, other.Id);
}
#endregion
public virtual TId Id { get; private set; }
public virtual string Name { get; private set; }
protected virtual IEqualityComparer<TId> IdComparer
{
get { return EqualityComparer<TId>.Default; }
}
}
An implementation would look like:
public sealed class RoofStyle : Enumeration<RoofStyle, int>
{
public static readonly RoofStyle Glass = new RoofStyle(0, "Glass Top", "GTR");
public static readonly RoofStyle ConvertibleSoft = new RoofStyle(1, "Convertible Soft Top", "CST");
public static readonly RoofStyle HardTop = new RoofStyle(2, "Hard Top", "HT ");
public static readonly RoofStyle Targa = new RoofStyle(3, "Targa Top", "TT ");
public static RoofStyle FromStringValue(string stringValue)
{
return AllValues.FirstOrDefault(value => value.StringValue == stringValue);
}
private RoofStyle(int id, string name, string stringValue) : base(id, name)
{
StringValue = stringValue;
}
public string StringValue { get; private set; }
}
You would use it during serialization like this:
var builder = new StringBuilder();
builder.Append(car.RoofStyle.StringValue);
...
To deserialize:
car.RoofStyle = RoofStyle.FromStringValue(EDIString.Substring(4, 3));
I don't see a problem with it - actually, I do the same. By this, I achieve verbosity with the enum, and can define how the enum is to be translated when I use it to request data, eg. RequestTarget.Character will result in "char".
Can't say I've ever seen it done that way but the consumer code is relatively simple so I'd probably enjoy using it.
The only thing that sticks out for me is the potential for consumers having to deal with nulls - which might be able to be removed. If you have control over the attributes (which you do, from the sounds of it), then there should never be a case where GetDisplayText or GetStringValue return null so you can remove
return attribs.Length > 0 ? attribs[0].StringValue : null;
and replace it with
return attribs[0].StringValue;
in order to simplify the interface for consumer code.
IMHO, the design is solid, and will work.
However, reflection tends to be a litle slow, so if those methods are used in tight loops, it might slow down the whole application.
You could try caching the the return values into a Dictionary<RoofStyle, string> so they are only reflected once, and then fetched from cache.
Something like this:
private static Dictionary<Enum, string> stringValues
= new Dictionary<Enum,string>();
public static string GetStringValue(this Enum value)
{
if (!stringValues.ContainsKey(value))
{
Type type = value.GetType();
FieldInfo fieldInfo = type.GetField(value.ToString());
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
stringValues.Add(value, attribs.Length > 0 ? attribs[0].StringValue : null);
}
return stringValues[value];
}
I know this question has already been answered, but while ago I posted the following code fragment on my personal blog, which demonstrates faking Java style enums using extension methods. You might find this method works for you, especially as it overcomes the overhead of accessing Attributes via reflection.
using System;
using System.Collections.Generic;
namespace ScratchPad
{
internal class Program
{
private static void Main(string[] args)
{
var p = new Program();
p.Run();
}
private void Run()
{
double earthWeight = 175;
double mass = earthWeight / Planet.Earth.SurfaceGravity();
foreach (Planet planet in Enum.GetValues(typeof(Planet))) {
Console.WriteLine("Your weight on {0} is {1}", planet, planet.SurfaceWeight(mass));
}
}
}
public enum Planet
{
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus,
Neptune
}
public static class PlanetExtensions
{
private static readonly Dictionary<Planet, PlanetData> planetMap = new Dictionary<Planet, PlanetData>
{
{Planet.Mercury, new PlanetData(3.303e+23, 2.4397e6)},
{Planet.Venus, new PlanetData(4.869e+24, 6.0518e6)},
{Planet.Earth, new PlanetData(5.976e+24, 6.37814e6)},
{Planet.Mars, new PlanetData(6.421e+23, 3.3972e6)},
{Planet.Jupiter, new PlanetData(1.9e+27, 7.1492e7)},
{Planet.Saturn, new PlanetData(5.688e+26, 6.0268e7)},
{Planet.Uranus, new PlanetData(8.686e+25, 2.5559e7)},
{Planet.Neptune, new PlanetData(1.024e+26, 2.4746e7)}
};
private const double G = 6.67300E-11;
public static double Mass(this Planet planet)
{
return GetPlanetData(planet).Mass;
}
public static double Radius(this Planet planet)
{
return GetPlanetData(planet).Radius;
}
public static double SurfaceGravity(this Planet planet)
{
PlanetData planetData = GetPlanetData(planet);
return G * planetData.Mass / (planetData.Radius * planetData.Radius);
}
public static double SurfaceWeight(this Planet planet, double mass)
{
return mass * SurfaceGravity(planet);
}
private static PlanetData GetPlanetData(Planet planet)
{
if (!planetMap.ContainsKey(planet))
throw new ArgumentOutOfRangeException("planet", "Unknown Planet");
return planetMap[planet];
}
#region Nested type: PlanetData
public class PlanetData
{
public PlanetData(double mass, double radius)
{
Mass = mass;
Radius = radius;
}
public double Mass { get; private set; }
public double Radius { get; private set; }
}
#endregion
}
}