Using Generics to Multiply Integers - c#

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;
}

Related

Convert from Java to C#

I need to write this code in C#. Any help would be appreciated.
The interface and the first class is where the issues are. How can I convert that into C#? EnumByteConverter & EnumByteConverter>?
Is this even possible? What would my options be?
public interface EnumByteConverter<E extends Enum<E> & EnumByteConverter<E>>
{
byte convert();
E convert(byte val);
}
public class ReverseByteEnumMap<V extends Enum<V> & EnumByteConverter>
{
private Map<Byte, V> map = new HashMap<>();
public ReverseByteEnumMap(Class<V> valueType)
{
for (V v : valueType.getEnumConstants())
{
map.put(v.convert(), v);
}
}
public V get(byte num)
{
return map.get(num);
}
}
public enum Transport implements EnumByteConverter<Transport>
{
FrameFormatB(0),
FrameFormatA(1),
FrameDraft(254),
FrameUnknown(255);
private static ReverseByteEnumMap<Transport> map = new ReverseByteEnumMap<>(Transport.class);
private final byte value;
Transport(int value)
{
this.value = (byte) value;
}
public byte convert()
{
return value;
}
public Transport convert(byte val)
{
return map.get(val);
}
public static Transport get(byte val)
{
return map.get(val);
}
}
This is what I have tried. I managed to implement the interface using struct, and the reverse class with similar thing.
public interface IEnumByteConverter<E> where E : struct
{
byte Convert();
E Convert(byte val);
}
}
public class ReverseByteEnumMap<T> where T : struct, IEnumByteConverter<T>
{
private Dictionary<Byte, T> map = new Dictionary<Byte, T>();
private IEnumByteConverter<T> converter;
public ReverseByteEnumMap(T valueType)
{
foreach (T t in Enum.GetValues(typeof(T)))
map.Add(t.Convert() , t);
}
public T Get(byte num)
{
return map[num];
}
}
public class Transport : IEnumByteConverter<TransportEnums>
{
public enum TransportEnums
{
FrameFormatB = 0,
FrameFormatA = 1,
FrameDraft = 254,
FrameUnknown = 255
}
private static ReverseByteEnumMap<Transport> map = new ReverseByteEnumMap<Transport> ();
private byte value;
Transport(int value)
{
this.value = (byte)value;
}
public byte Convert()
{
return value;
}
public TransportEnums Convert(byte val)
{
return map.Get(val);
}
public static TransportEnums Get(byte val)
{
return map.Get(val);
}
}
But I got stuck in the last class. I cannot use the Transport.class nor enums. I cannot tell if this a right path I am heading on
In C# it is (quite) easy to change the base type of an enum:
public enum Transport : byte
{
FrameFormatB = 0,
FrameFormatA = 1,
FrameDraft = 254,
FrameUnknown = 255
}
and it is quite easy to convert from the enum to the base type and back:
Transport t1 = (Transport)255; // Equivalent to = Transport.FrameUnknown
int i1 = (int)t1; // 255
byte b1 = (byte)t1; // 255
So you don't need all the support code that you wrote.
In Java enum are classes that don't normally have a "value", and if you want to give them a numerical value you have to do like what is written in your code: define a value field. Then you have to add methods to go from the enum "name" to its "value" and back.
The main problem here is that the C# (.NET) enum can in truth have any value, not only the defined ones:
Transport t2 = (Transport)100;
while in Java only the defined values of enum are legal (because they are the only instances of the enum class that are defined. Other instances can't be created). See for example https://stackoverflow.com/a/469315/613130 .
The code you wrote is quite similar to this one: http://dan.clarke.name/2011/07/enum-in-java-with-int-conversion/

Constrain generic to be a nullable type

I'm looking for sample usage something like this:
Foo<string> stringFoo = new Foo<string>("The answer is");
Foo<int> intFoo = new Foo<int>(42);
// The Value of intFoo & stringFoo are strongly typed
stringFoo.Nullify();
intFoo.Nullify();
if (stringFoo == null && intFoo == null)
MessageBox.Show("Both are null);
Given this class Foo, I can auto-wrap T into a nullable:
public class Foo1<T>
where T : struct
{
private T? _value;
public Foo(T? initValue)
{
_value = initValue;
}
public T? Value { get { return _value; } }
public void Nullify { _value = null; }
}
This works for primitives, but not with String or other classes.
Next flavor works for strings, but not primitives:
public class Foo2<T>
{
private T _value;
public Foo(T initValue)
{
_value = initValue;
}
public T Value { get { return _value; } }
public void Nullify { _value = default(T); }
}
I could use Nullable<int> for Foo2 and the code would work like this:
Foo2<int?> intFoo = new Foo<int?>(42);
But this is error prone because it fails for Foo2. If I could constrain T to be types that support nullability then that would be fine.
So after all of that, is there any way to constrain T to be a nullable type?
Some additional notes: .NET 4.0, VS2010. And I did find one similar question to this on here, but without a succesful answer.
There's no constraint you can apply for this, but you can test for it at execution time:
if (default(T) != null)
{
throw new SomeAppropriateException(typeof(T) + " is not a nullable type");
}
You could even put that into a static constructor, which would make sure it only executed once per constructed type - and anyone trying to use Foo<int> anywhere would have a hard time ignoring the TypeInitializerException. That's not terribly friendly for a public API, but I think it's reasonable for an internal one.
EDIT: There is one horrible way of making it harder to create instances of Foo<int>... you could use the ghastly code in this blog post (using overload resolution rules along with default parameters and a couple of constrained generic types) and mark the overload which aims at a non-nullable value type as obsolete with an error. That way, Foo<int> would still be a valid type, but you'd be hard-pressed to create an instance of it. I'm not going to recommend that you do this though...
You might be able to make the constructor of Foo<T> internal, and require that new instances can only be created through a factory class:
public class Foo<T>
{
private T value;
internal Foo(T value)
{
this.value = value;
}
public void Nullify()
{
this.value = default(T);
}
public T Value { get { return this.value; } }
}
public class Foo
{
public static Foo<T> Create<T>(T value) where T : class
{
return new Foo<T>(value);
}
public static Foo<T?> Create<T>(T? value) where T : struct
{
return new Foo<T?>(value);
}
}
I don't like it as much as the syntax of Foo1, but here is Foo3:
public class Foo3<T>
where T : struct
{
private T _value;
private T _nullValue;
public Foo3(T initValue)
: this(initValue, default(T))
{
}
public Foo3(T initValue, T nullValue)
{
_value = initValue;
_nullValue = nullValue;
}
public T Value { get { return _value; } }
public bool IsNull
{
get
{
return object.Equals(_value, _nullValue);
}
}
public void Nullify() { _value = _nullValue; }
}
And then my usage becomes:
Foo3<string> stringFoo = new Foo<string>("The answer is");
Foo3<int> intFoo = new Foo<int>(42, int.MinValue);
stringFoo.Nullify();
intFoo.Nullify();
if (stringFoo.IsNull && intFoo.IsNull)
MessageBox.Show("Both are null);
This is still error prone because getting the Value property of Foo3 (and Foo2) is not straightforward. Foo1 was the best because automatically wrapped the Value will null support.
I might just need ValueTypeFoo and ObjectFoo and deal with two versons.

Simulate variadic templates in C#

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.

How to make your object act as another type when comparing?

I do not remember how to do in C# a comparison of a class against a primitive type.
Example
public class Validate{
... //This is here that we would need to add code
//if I remember to make the object act as a boolean for example
}
...
Validate v = new Validate(...);
if(v==true)
{
...
}
Do you know the name of that and how to do it?
I think you're looking for an implicit type conversion.
Add the following method to your Validate class:
public static implicit operator bool(Validate v)
{
// Logic to determine if v is true or false
return true;
}
To do what you want, you need to override the implicit cast operator:
public class MyObject
{
private int i;
public MyObject(int i)
{
this.i = i;
}
public static implicit operator bool(MyObject o)
{
return o.i % 2 == 0;
}
}
The above example will evaluate to true if the field i is even:
MyObject o1 = new MyObject(1);
MyObject o2 = new MyObject(2);
if (o1)
{
Console.WriteLine("o1");
}
if (o2)
{
Console.WriteLine("o2");
}
The output of the above is o2.
However, it is a bit of a horrible implementation as it leads to confusing code in that you have constructs that read as if (object), which would be unfamiliar to most readers - if (object.IsValid) makes the intention much more clearer.
do you mean operator overloading?
public static bool operator == (Validate v, bool value)
{
return /* some comparison */
// or going off of the other posters answer
return v.IsValid == value;
}
Just add an IsValid property to your Validate class and call that property:
public class Validate
{
public bool IsValid
{
get { [implementation here] }
}
}
...
Validate v = new Validate(...);
if(v.IsValid)
{
...
}
It is possible to create an implicit operator, but it is not advisable to use it this way, because it would make your code hard to follow for other developers.
UPDATE
Okay, just for completeness and education, this is how to do it:
public class Validate
{
public bool IsValid
{
get { [implementation here] }
}
public static implicit operator bool(Validate v)
{
return v.IsValid;
}
}
But again, don't do it. It would make your code pretty hard to follow.

Using an enum as an array index in C#

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]);
}
}
}

Categories