So I have a program for this class where I'm supposed to allow the user to select a data type like byte, int, short, long, and etc. And then I am supposed to validate and make sure that the numbers they enter for the math problem aren't outside of the bounds of the data type they selected. Right now I'm using a bunch of if statements for each individual data type, and checking if it's above MaxValue or below MinValue. However, there has to be a better way to do this, right?
My current code is like this (numType is a byte set to the value of a constant when the button is pressed):
if(numType = BYTE){
if(leftNum > byte.MaxValue){
errorsEncountered = true;
returnString = returnString + "Left number must not be more than " +
byte.MaxValue.ToString() + " for a byte.\n";
}
if(leftNum < byte.MinValue){
errorsEncountered = true;
returnString = returnString + "Left number must not be less than " +
byte.MinValue.ToString() + " for a byte.\n";
... (so on and so forth)
}
However I'd like to think that you could instead use something like a variable to record the data type and use that instead. So lets say that you have an array of each potential value of numType (1-7 in this case). Would there be a way to do something like this?
byte numType = 8; // Will never be returned as this, an error is output for this value immediately.
const byte BYTE = 0;
const byte SHORT = 1;
const byte INT = 2;
const byte LONG = 3;
const byte FLOAT = 4;
const byte DOUBLE = 5;
const byte DECIMAL = 6;
string[] dataTypes = {"byte", "short", "int", "long", "float", "double", "decimal"};
if(leftNum > dataTypes[numType].MaxValue) {
errorsEncountered = true;
returnString = "Left number must not be more than " +
dataTypes[numType].MaxValue.ToString() + " for a " + dataTypes[numType] + ".";
}
if(leftNum < dataTypes[numType].MinValue) {
errorsEncountered = true;
returnString = "Left number must not be more than " +
dataTypes[numType].MinValue.ToString() + " for a " + dataTypes[numType] + ".";
}
I know my demonstration is incredibly simplistic but I genuinely don't know how better to describe what I'm trying to do. Thank you for any help you can provide.
Edit: Honestly it seems I'm a bit out of my depth here. I have no clue what most of these solutions are actually doing, and I've come out of this with the impression that I should probably just work on learning the language as a whole.
You can keep a dictionary of all the types you want to use with the string you want the user to type in to refer to that type, then use reflection to call TryParse and MinValue/MaxValue if needed.
Something like this:
public static readonly Dictionary<string, Type> aliases = new() {
{ "byte", typeof(byte) },
{ "short" , typeof(short) },
{ "int" , typeof(int) },
{ "long" , typeof(long) },
{ "float" , typeof(float) },
{ "double" , typeof(double) },
{ "decimal" , typeof(decimal) }
};
static void Main() {
Type type;
while (true) {
Console.WriteLine("Enter the type:");
var selectedType = Console.ReadLine().Trim();
if (!aliases.TryGetValue(selectedType, out type)) {
Console.WriteLine("You did it wrong");
continue;
}
break;
}
while (true) {
Console.WriteLine("Type a value:");
var value = Console.ReadLine().Trim();
// Create an instance of whatever type we're using
object result = Activator.CreateInstance(type);
// Get a reference to the TryParse method for this type
var tryParseMethod = type.GetMethod("TryParse", new[] { typeof(string), type.MakeByRefType() });
// Call TryParse
if (tryParseMethod.Invoke(null, new[] { value, result }) is bool success && success) {
Console.WriteLine("You did it right!");
break;
} else {
// TryParse failed, so show the user the min/max values
var minValueProp = type.GetField("MinValue");
var maxValueProp = type.GetField("MaxValue");
Console.WriteLine($"You did it wrong. Enter a value between {minValueProp.GetValue(result)} and {maxValueProp.GetValue(result)}");
continue;
}
}
}
For example:
Enter the type:
byte
Type a value:
-1
You did it wrong. Enter a value between 0 and 255
Type a value:
1
You did it right!
A bit more of code would be helpful, for instance how leftNum and numType are declared.
Let's try to help anyway. You can try a polymorphic approach.
It may be overkill, but it's a nice exercise:
Create an interface, let's say ITypeValidator
Create the implementations of such Interface, i.e. IntegerValidator : ITypeValidator
Have a Dictionary containing your validators and their respective type Dictionary<byte, ITypeValidator>
Initialize your types in your Dictionary.
Sample:
internal class Program
{
static void Main(string[] args)
{
var myTypes = GetTypesImplementingInterface();
byte numType = 2;
object leftNum = 3;
var validator = myTypes[numType];
var result = validator.Validate(leftNum);
}
public static Dictionary<byte, ITypeValidator> GetTypesImplementingInterface()
{
// Fancy approach would be to use reflection to scan the Assembly
// for implementations of our interface and automatically
// instantiate and fill in the Dictionary
return new Dictionary<byte, ITypeValidator>()
{
{ 2, new IntValidator() }
};
}
public interface ITypeValidator
{
byte TypeNumber { get; } // Tip: this helps with the Reflection approach
ValidationResult Validate(object number);
}
public class ValidationResult
{
public bool HasError { get; set; }
public List<string> ErrorMessages { get; set; }
}
public class IntValidator : ITypeValidator
{
public byte TypeNumber => 2;
public ValidationResult Validate(object number)
{
// do your things
return new ValidationResult();
}
}
}
If your validations are always the same (min and max), you can also think of adding a base class, with abstract Minimum and Maximum properties and a base validation method. So for each type, you just need to implement the TypeNumber, Min and Max values.
I'm pretty new to TDD and I have a hard time to understand how to test private members of the class (I know! It's private, shouldn't be tested - but please keep reading). We might have a public function which sets private property and other public function that returns "something" based on that private property.
Let me show you a basic example:
public class Cell
{
public int X { get; set; }
public int Y { get; set; }
public string Value { get; set; }
}
public class Table
{
private Cell[,] Cells { get; }
public Table(Cell[,] cells)
{
Cells = cells;
}
public void SetCell(int x, int y, string value)
{
Cells[x, y].Value = value;
}
public void Reset()
{
for (int i = 0; i < Cells.GetLength(0); i++)
{
for (int j = 0; j < Cells.GetLength(1); j++)
{
Cells[i, j].Value = "";
}
}
}
public bool AreNeighborCellsSet(int x, int y)
{
bool areNeighborCellsSet = false;
// checking...
return areNeighborCellsSet;
}
}
In this example Cells are private, because there's no reason to make them public. I don't need to know what's the value of particular Cell outside this class. I just need an information if neighbor cells are empty.
1. How can I test Reset method?
Technically I should create a Table with mocked array of cells. Call Reset and then assert if every cell has empty Value. But I can't actually check if they are empty or not.
2. In this case I would call Assert many times (for every cell) - is it a good practice? I've read that "It's not!", but Reset resets all cells, so I have to somehow check every cell.
EDIT:
Option 2:
public class Table
{
private Cell[,] Cells { get; }
public Table(int height, int width, ICellFactory cellFactory)
{
Cells = new ICell[height, width];
for (int i = 0; i < Cells.GetLength(0); i++)
{
for (int j = 0; j < Cells.GetLength(1); j++)
{
Cells[i, j].Value = cellFactory.Create(i, j);
}
}
}
// Rest is the same...
}
Your class have three public methods
void SetCell
void Reset
bool AreNeighborCellsSet
So all functionality should be tested only through those methods and with possible help of constructor input arguments.
I am afraid you are not doing TDD, because you are trying to test already implemented logic (for loop of internal member). With TDD you should write unit tests by using only public API of class under test.
When you test Reset method you should think how it affect on results of other public methods. Table class has only one method which return some value we can observe - bool AreNeighborCellsSet - so seems like this is the only method against which we can execute our asserts.
For Reset method you need to set cells so that AreNeighborCellsSet returns true. Then execute Reset and assert that now AreNeighborCellsSet returns false.
[Test]
public void AfterResetGivenCellShouldNotHaveNeighbors()
{
// Arrange
var cell = new Cell { X = 1, Y = 1, Value = "central" };
var neighborCell = new new Cell { X = 1, Y = 2, Value = "neighbor" };
var table = new Table(new[] { cell, neighborCell });
// table.AreNeighborCellsSet(cell.X, cell.Y) - should return true at this moment
// Act
table.Reset();
// Assert
table.AreNeighborCellsSet(cell.X, cell.Y).Should().BeFalse();
}
This is a good example of TDD (Test-Driven Development), where problems with testing is good sign that something wrong with design.
Actually, I think, in your case you don't need Reset method at all - just create a new instance of Table every time you need to reset it.
The answer of Ignas my be a workaround for the problem but I feel a need to clarify some design issues here:
Basically there is no need to check if loop iterates through whole collection. That is tested by the framework team in MS.
What you need to do is to check if your new type (in this case Cell) behaves properly.
In my opinion you're violating the SRP. There is really no need for Table class to know how to reset this particular implementation of Cell. If some day you decide to create a cell able to contain a picture let's say, you'll most likely feel a need to clear it in some other way than by setting an empty string to it's Value property.
Start with abstracting Cell to an interface. Then just add method Reset() to the Cell and call it in the loop in Table class for every cell.
That would allow you to create tests for your implementation of Cell and there you can check if after calling Reset() cell's value truly becomes null or empty or whatever you need :-)
There are ways to test private properties with no need for changing your code or adding extra code to your tested class, you can use testing tools that allows you to do so.
for example i used Typemock to change the logic of the Table c'tor to create a populated table and to get the private property Cells after calling the reset method:
public void TestMethod1()
{
var handle = Isolate.Fake.NextInstance<Table>(Members.CallOriginal, context =>
{
var tempcells = context.Parameters[0] as Cell[,];
for (int i = 0; i < tempcells.GetLength(0); i++)
{
for (int j = 0; j < tempcells.GetLength(1); j++)
{
tempcells[i, j] = cellFactory.Create(i, j);
}
}
context.Parameters[0] = tempcells;
//calling the original ctor with tempcells as the parameter
context.WillCallOriginal();
});
// calling the ctor with the custom logic
var testTable = new Table(new Cell[2,2]);
testTable.Reset();
// calling the private property
var resTable = Isolate.Invoke.Method(testTable, "get_Cells") as Cell[,];
// for asserting
var emptyCell = new Cell { Value = string.Empty };
for (int i = 0; i < 2; i++)
{
for(int j=0; j<2; j++)
{
Assert.AreEqual(emptyCell.Value, resTable[i, j].Value);
}
}
}
As Zegar mentioned in comments there could be several code design considerations, and probably writing tests first aka using TDD would help not to even run into such situations, however I think there is a simple workaround as well.
You are passing array as reference into Table class and not overriding it, therefore you can access the array outside of Table class even though you are modifying it inside the class.
You don't need to do many asserts, you just need to arrange an expected array for assertion. Use FluentAssertions and specifically ShouldBeEquivalentTo() which is a very nice solution for arrays comparison. Nuget package.
Sample test below.
[TestMethod]
public void TestMethod1()
{
// Arrange
var expectedCells = new Cell[2, 2];
expectedCells[0, 0] = new Cell { Value = string.Empty };
expectedCells[0, 1] = new Cell { Value = string.Empty };
expectedCells[1, 0] = new Cell { Value = string.Empty };
expectedCells[1, 1] = new Cell { Value = string.Empty };
var cells = new Cell[2,2];
cells[0,0] = new Cell { Value = "00" };
cells[0,1] = new Cell { Value = "01" };
cells[1,0] = new Cell { Value = "10" };
cells[1,1] = new Cell { Value = "11" };
var table = new Table(cells);
// Act
table.Reset();
// Assert
cells.ShouldBeEquivalentTo(expectedCells); // using FluentAssertions
}
To summarize and answer your questions.
Test cells array you pass into the constructor.
Ideally you want to have a single assert per test, if possible.
I've just started out with C# reflection, and I ran into the issue of calling methods that take internal classes as arguments:
Sample class:
public class MyClass
{
public class CustomColor
{
public int h;
public int s;
public int v;
}
public string[] ConvertColors(List<CustomColor> colors)
{
//...
}
}
The code I'm using to call other methods in this class :
FieldInfo info = cInstanceContainerObject.GetType().GetField("_myClass", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
dynamic myClassObject = info.GetValue(cInstanceContainerObject);
Allowing me to do this :
myClassObject.SomeSampleMethod(int sampleParam);
However, I'm stuck on figuring out how to create the proper parameters for the ConvertColors method above. :(
I am not sure how you created your cInstanceContainerObject. I am using MethodInfo.Invoke. Below is the code:
//Your class
public class MyClass
{
public class CustomColor
{
public int h;
public int s;
public int v;
}
public string[] ConvertColors(List<CustomColor> colors)
{
return new string[]{"1"};
}
}
//Usage
MyClass mc = new MyClass();
MyClass.CustomColor cc = new MyClass.CustomColor();
Type t = mc.GetType();
MethodInfo mi = t.GetMethod("ConvertColors");
List<MyClass.CustomColor> lst = new List<MyClass.CustomColor>
{
new MyClass.CustomColor(),
new MyClass.CustomColor()
};
var x = (string[])mi.Invoke(mc,new object[]{lst});
Console.WriteLine (x.Count());
Tom,
Try passing the color you wish to convert as a reference.
In the example below, the color (CustomColor) you pass in as a reference will be updated, instead of returning strings.
So, instead of calling the method like:
string[] colors = ConvertColors(yourColorList, foo, bar);
it can instead be called as:
ConvertColors(yourColorList, foo, bar);
Example:
public class MyClass
{
public class CustomColor
{
public int h;
public int s;
public int v;
}
public enum Convert { H, S, V, HS, HV, SV, HSV };
public void ConvertColors(ref List<CustomColor> colors, Convert type,
ref CustomColor changeAmt)
{
// Variables to change H, S, and V from changeAmt parameter:
int changeH = changeAmt.h;
int changeS = changeAmt.s;
int changeV = changeAmt.v;
// Change the actual colors which were passed as 'colors' parameter.
switch (type)
{
// Change H.
case Convert.H:
foreach (CustomColor c in colors)
c.h += changeH;
break;
// Change S.
case Convert.S:
foreach (CustomColor c in colors)
c.s += changeS;
break;
// Change V.
case Convert.V:
foreach (CustomColor c in colors)
c.v += changeV;
break;
// Change HS.
case Convert.HS:
foreach (CustomColor c in colors)
{
c.h += changeH;
c.s += changeS;
}
break;
// Change HV.
case Convert.HV:
foreach (CustomColor c in colors)
{
c.h += changeH;
c.v += changeV;
}
break;
// Change SV.
case Convert.SV:
foreach (CustomColor c in colors)
{
c.s += changeS;
c.v += changeV;
}
break;
// Change HSV.
case Convert.HSV:
foreach (CustomColor c in colors)
{
c.h += changeH;
c.s += changeS;
c.v += changeV;
}
break;
}
}
}
Explanation:
'enum' allows you to create a custom parameter for your method:
public enum Convert { H, S, V, HS, HV, SV, HSV };
the 'switch' statement allows you to handle those parameters:
switch (type)
{
case Convert.H:
// Do something
return;
case Convert.S:
// Do something
return;
case Convert.V:
// Do something
return;
Create an instance of the changes you want to make as a new CustomColor, and pass a reference to the list of CustomColors, your custom parameter, and a reference to the changes as a CustomColor:
private void AnyMethod()
{
// Create first custom color.
CustomColor color1 = new CustomColor();
color1.h = 50;
color1.s = 25;
color1.v = 35;
// Create second custom color.
CustomColor color2 = new CustomColor();
color2.h = 50;
color2.s = 25;
color2.v = 35;
// Create third custom color.
CustomColor color3 = new CustomColor();
color3.h = 50;
color3.s = 25;
color3.v = 35;
// Add to list of custom colors.
List<CustomColor> colorList = new List<CustomColor>();
colorList.Add(color1);
colorList.Add(color2);
colorList.Add(color3);
// Create changes as a new color.
CustomColor colorChange = new CustomColor();
colorChange.h = -10;
colorChange.s = 47;
colorChange.v = -15;
// Update all colors in your list.
ConvertColors(ref colorList, Convert.HSV, ref colorChange); // BOOM.
}
If you wish to get the strings afterwards:
string[] hsvStrings =
{
color1.h.ToString(),
color1.s.ToString(),
color1.v.ToString(),
// Continue...
};
After a sleepless night I actually figured out how to achieve this. Both answers did help me see the possibilities that led me to the answer, however I had to achieve this without referencing the foreign DLL, or doing any modifications to it, just get an instance of it's main object through Reflection, and then call the various methods within it (some of which required classes only provided by the DLL itself as you can see in my example).
My solution is like this (feel free to provide better alternatives) :
Get a Type of both the List and CustomColor each, by utilizing the method parameter:
Type listType = myClassObject.GetType()
.GetMethod("ConvertColors")
.GetParameters()[0]
.ParameterType;
Type colorType = myClassObject.GetType()
.GetMethod("ConvertColors")
.GetParameters()[0]
.ParameterType
.GetProperty("Item")
.PropertyType;
Then create individual instances of both the entire list and individual CustomColors using Activator:
dynamic colorList = Activator.CreateInstance(listType);
dynamic customColor = Activator.CreateInstance(colorType);
colorList.Add(customColor);
myClassObject.ConvertColors(colorList); //works!
I have an enum which is defined like this:
public enum eRat { A = 0, B=3, C=5, D=8 };
So given value eRat.B, I want to get the next one which is eRat.C
The solution I see is (without range checking)
Array a = Enum.GetValues(typeof(eRat));
int i=0 ;
for (i = 0; i < a.GetLength(); i++)
{
if (a.GetValue(i) == eRat.B)
break;
}
return (eRat)a.GetValue(i+1):
Now that is too much complexity, for something that simple. Do you know any better solution?? Something like eRat.B+1 or Enum.Next(Erat.B)?
Thanks
Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:
public static class Extensions
{
public static T Next<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) + 1;
return (Arr.Length==j) ? Arr[0] : Arr[j];
}
}
The beauty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:
return eRat.B.Next();
Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next().
Probably a bit overkill, but:
eRat value = eRat.B;
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.SkipWhile(e => e != value).Skip(1).First();
or if you want the first that is numerically bigger:
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.First(e => (int)e > (int)value);
or for the next bigger numerically (doing the sort ourselves):
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.Where(e => (int)e > (int)value).OrderBy(e => e).First();
Hey, with LINQ as your hammer, the world is full of nails ;-p
Do you really need to generalize this problem? Can you just do this instead?
public void SomeMethod(MyEnum myEnum)
{
MyEnum? nextMyEnum = myEnum.Next();
if (nextMyEnum.HasValue)
{
...
}
}
public static MyEnum? Next(this MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.A:
return MyEnum.B;
case MyEnum.B:
return MyEnum.C;
case MyEnum.C:
return MyEnum.D;
default:
return null;
}
}
The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:
public static class eRat
{
public static readonly eRatValue A;
public static readonly eRatValue B;
public static readonly eRatValue C;
public static readonly eRatValue D;
static eRat()
{
D = new eRatValue(8, null);
C = new eRatValue(5, D);
B = new eRatValue(3, C);
A = new eRatValue(0, B);
}
#region Nested type: ERatValue
public class eRatValue
{
private readonly eRatValue next;
private readonly int value;
public eRatValue(int value, eRatValue next)
{
this.value = value;
this.next = next;
}
public int Value
{
get { return value; }
}
public eRatValue Next
{
get { return next; }
}
public static implicit operator int(eRatValue eRatValue)
{
return eRatValue.Value;
}
}
#endregion
}
This allows you to do this:
int something = eRat.A + eRat.B;
and this
eRat.eRatValue current = eRat.A;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.
EDIT
I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:
Do use an enumeration to strongly type
parameters, properties, and return
values that represent sets of values.
I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.
You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.
Works up to "C" since there is no answer on what to return after "D".
[update1]: Updated according to Marc Gravell's suggestion.
[update2]: Updated according to how husayt's wanted - return "A" for the next value of "D".
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
}
}
public enum eRat { A = 0, B = 3, C = 5, D = 8 };
public class eRatEnumHelper
{
public static eRat GetNextEnumValueOf(eRat value)
{
return (from eRat val in Enum.GetValues(typeof (eRat))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
}
Result
Next enum of A = B
Next enum of B = C
Next enum of C = D
Next enum of D = A
Thanks you all, for your inspiration and solutions.
Here are my results, as an extension.
using System;
using System.Linq;
public static class Enums
{
public static T Next<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
public static T Previous<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).Reverse().SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
}
use:
using System;
using System.Linq;
public enum Test { F1, F2, F3 }
public class Program
{
public static void Main()
{
Test t = Test.F3;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
Console.WriteLine("\n");
t = Test.F1;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
}
}
result:
F3
F1
F2
F1
F2
F3
Are you locked into using an enum by something that you have no control over?
If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;
If you create a Dictionary and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.
If you must use the enum, I'd suggest something else:
var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.
For simple solution, you might just extract array from enum.
eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
Then you can enumerate
foreach (eRat item in list)
//Do something
Or find next item
int index = Array.IndexOf<eRat>(list, eRat.B);
eRat nextItem = list[index + 1];
Storing the array is better than extracting from enum each time you want next value.
But if you want more beautiful solution, create the class.
public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
int _index;
T[] _list;
public EnumEnumerator() {
if (!typeof(T).IsEnum)
throw new NotSupportedException();
_list = (T[])Enum.GetValues(typeof(T));
}
public T Current {
get { return _list[_index]; }
}
public bool MoveNext() {
if (_index + 1 >= _list.Length)
return false;
_index++;
return true;
}
public bool MovePrevious() {
if (_index <= 0)
return false;
_index--;
return true;
}
public bool Seek(T item) {
int i = Array.IndexOf<T>(_list, item);
if (i >= 0) {
_index = i;
return true;
} else
return false;
}
public void Reset() {
_index = 0;
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>)_list).GetEnumerator();
}
void IDisposable.Dispose() { }
object System.Collections.IEnumerator.Current {
get { return Current; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _list.GetEnumerator();
}
}
Instantiate
var eRatEnum = new EnumEnumerator<eRat>();
Iterate
foreach (eRat item in eRatEnum)
//Do something
MoveNext
eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
Judging from your description, you don't really want an enum. You're stretching enum beyond its capabilities. Why not create a custom class that exposes the values you need as properties, while keeping them in OrderedDictionary.
Then getting a next/previous one would be trivial.
--update
If you want to enumerate differently on the collection based in the context, make that explicit part of your design.
Encapsulate the items within a class, and have few methods each returning IEnumerable where, T is your desired type.
For example
IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()
etc...
You could simplify it and generalize it some:
static Enum GetNextValue(Enum e){
Array all = Enum.GetValues(e.GetType());
int i = Array.IndexOf(all, e);
if(i < 0)
throw new InvalidEnumArgumentException();
if(i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return (Enum)all.GetValue(i + 1);
}
EDIT:
Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:
enum BRUSHSTYLE{
SOLID = 0,
HOLLOW = 1,
NULL = 1,
HATCHED = 2,
PATTERN = 3,
DIBPATTERN = 5,
DIBPATTERNPT = 6,
PATTERN8X8 = 7,
DIBPATTERN8X8 = 8
}
Given either BRUSHSTYLE.NULL or BRUSHSTYLE.HOLLOW, the return value would be BRUSHSTYLE.HOLLOW.
<leppie>
Update: a generics version:
static T GetNextValue<T>(T e)
{
T[] all = (T[]) Enum.GetValues(typeof(T));
int i = Array.IndexOf(all, e);
if (i < 0)
throw new InvalidEnumArgumentException();
if (i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return all[i + 1];
}
</leppie>
#leppie:
Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.
Hope this part of my code helps you:
public enum EGroupedBy
{
Type,
InterfaceAndType,
Alpha,
_max
}
private void _btnViewUnit_Click(object sender, EventArgs e)
{
int i = (int)GroupedBy;
i = (i + 1) % (int)EGroupedBy._max;
GroupedBy = (EGroupedBy) i;
RefreshUnit();
}
Old post, but I have an alternative solution
//Next with looping
public static Enum Next(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) + 1;
return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
}
//Previous with looping
public static Enum Prev(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) - 1;
return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
}
And when you need to use it, just do a cast
BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
var next = (BootstrapThemeEnum)theme.Next();
my enum
public enum BootstrapThemeEnum
{
[Description("white")]
White = 0,
[Description("default")]
Default = 1,
[Description("info")]
Info = 2,
[Description("primary")]
Primary = 3,
[Description("success")]
Success = 4,
[Description("warning")]
Warning = 5,
[Description("danger")]
Danger = 6,
[Description("inverse")]
Inverse = 7
}
I can think of 2 things:
eRat.B+3
Enum.Parse(typeof(((int)eRat.B)+3)
var next = (eRat)((int)someRat + 3);
Seems like an abuse of the enum class to me - but this would do it (assuming that calling Next on the last value would cause wrap-around):
public static eRat Next(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.A;
}
}
And this would give you the previous value on the same basis:
public static eRat Previous(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.D;
}
}
I'm using this, perfect for my.
//===================================================================================
// NEXT VALUE IN ENUM
// ex: E_CamModes eNew = kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
public static T eGetNextValue< T >( T eIn ){
T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
int iVal = System.Array.IndexOf( aiAllValues, eIn );
return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
}
There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum, isn't a problem. It is still the integer (or whatever underlying number type you assign). Enum just adds the complexity of a cast requirement.
Assume your enum is defined like this:
public enum ItemStatus
{
New = 0,
Draft = 1,
Received = 2,
Review = 4,
Rejected = 8,
Approved = 16
}
ItemStatus myStatus = ItemStatus.Draft;
Use bitwise operations on the Enum. For Example:
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.Received.
You can also go backwards down the Enum by changing the bitwise operator from << to >>.
myStatus = (ItemStatus)(((int)myStatus) >> 1)
The result is of myStatus is: ItemStatus.New.
You should always add code to test for an "out of bounds" situation in both directions.
You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301
I would go with Sung Meister's answer but here is an alternative:
MyEnum initial = MyEnum.B, next;
for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
{
if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
{
next = (MyEnum) i;
break;
}
}
Note: many assumptions assumed :)
From comments I had many question like: "Why would you ever want to use enum in this way." Since so many of you asked, let me give you my use case and see if you agree then:
I have a fixed array of items int[n]. Depending on the situation I want to enumerate through this array differently. So i defined:
int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 };
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D };
void walk(Type enumType)
{
foreach (Type t in Enum.GetValues(enumType))
{
write(t.ToString() + " = " + Arr[(int)t)];
}
}
and call walk(typeof(eRAt1)) or walk(typeof(eRAt2))
then i get required output
1) walk(typeof(eRAt1))
A = 1
B = 5
C = 78
D = 30
2) walk(typeof(eRAt2))
A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30
This is very simplified. But i hope, this explains. There are some other advantages to this, as having enum.toString(). So basically i use enums as indexers.
So using the solution I can do something like this now.
In sequence eRat1 next value to B is C, but in eRat2 it is BB.
So depending on which sequence I am interested in, I can do e.next and depending on enumType I will either get C or BB. How would one achieve that with dictionaries?
I think this a rather elegant use of enums.
I'm using this here:
public MyEnum getNext() {
return this.ordinal() < MyEnum.values().length - 1 ?
MyEnum.values()[this.ordinal() + 1] :
MyEnum.values()[0];
}
LINQ solution that does not break on last element but continues at the default again:
var nextValue = Enum.GetValues(typeof(EnumT)).Cast<EnumT>().Concat(new[]{default(EnumT)}).SkipWhile(_ => _ != value).Skip(1).First();
I tried the first solution but it did not work for me. Below is my solution:
public object NextEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum) throw new
ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr,currentEnumItem) + 1;
return (Arr.Length == j) ? currentEnumItem : Arr.GetValue(j);
}
public object PreviousEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum)
throw new ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr, currentEnumItem) - 1;
return (j==-1) ? currentEnumItem : Arr.GetValue(j);
}
I did something similar with a different enum. It's for a game and the player has the chance to toggle colors.
public enum PlayerColor {
Red = 0, Green, Blue, Cyan, Yellow, Orange, Purple, Magenta
}
public PlayerColor GetNextFreeColor(PlayerColor oldColor) {
PlayerColor newColor = (PlayerColor)((int)(oldColor + 1) % 8);
return newColor;
}
This solution worked for me.
Based on best answer from Yahya Hussein here is edit of his code for Previous element in Enum
public static class Extensions
{
public static T Previous<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) - 1;
return (j < 0) ? Arr[Array.Length - 1] : Arr[j];
}
}
enum Level
{
Easy,
Medium,
Expert
};
public static void Main()
{
var difficulty = Level.Easy;
var level = (int)difficulty;
Console.WriteLine(difficulty);
Console.WriteLine(level);
Console.WriteLine("promote level");
level++;
Console.WriteLine(level);
difficulty = (Level)level;
Console.WriteLine(difficulty);
}
You can add and remove integers to an enum to obtain the next value. The only problem is that integer operations on the enum will not check the validity of the enum itself, thus could set "invalid" values.
But you can combine the ++enum and the Enum.IsDefined() to obtain a simple way to get next and previous values of your enum. This would be inefficient in your case since the integer values are not continuous, but if you have continuous integers then it works nicely, and one can check when the ++enum is out of range. Check the next example.
public enum level
{
a = 0,
b = 1,
c = 2,
d = 3,
e = 4
}
private static void Main(string[] args)
{
var levelValue = level.a;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
}
The output for this would be:
a
b
c
d
e
False
5
e
d
c
b
True
a
False
-1