Can you loop through an enum in C#? - c#

for (int i = (int)MY_ENUM.First; i <= (int)MY_ENUM.Last; i++)
{
//do work
}
Is there a more elegant way to do this?

You should be able to utilize the following:
foreach (MY_ENUM enumValue in Enum.GetValues(typeof(MY_ENUM)))
{
// Do work.
}

Enums are kind of like integers, but you can't rely on their values to always be sequential or ascending. You can assign integer values to enum values that would break your simple for loop:
public class Program
{
enum MyEnum
{
First = 10,
Middle,
Last = 1
}
public static void Main(string[] args)
{
for (int i = (int)MyEnum.First; i <= (int)MyEnum.Last; i++)
{
Console.WriteLine(i); // will never happen
}
Console.ReadLine();
}
}
As others have said, Enum.GetValues is the way to go instead.

Take a look at Enum.GetValues:
foreach (var value in Enum.GetValues(typeof(MY_ENUM))) { ... }

The public static Array GetValues(Type enumType) method returns an array with the values of the anEnum enumeration. Since arrays implements the IEnumerable interface, it is possible to enumerate them.
For example :
EnumName[] values = (EnumName[])Enum.GetValues(typeof(EnumName));
foreach (EnumName n in values)
Console.WriteLine(n);
You can see more detailed explaination at MSDN.

Related

Having two param lists with same size

The method PrintTimes(string a, int b) prints the string a, b times (i.e. PrintTimes("test",3) will print testtesttest).
I want to create a method, which will get a params array of strings and a params array of integers. So the call function will ook like this
PrintTimes("A","B","C","D",2,1,3,2);
Or
PrintTimes("A",2,"B",1,"C",3,"D",2)
Both of which will print AABCCCDD
Since there can be only one params parameter in a method, this is impossible. So is there a way to do this?
I know I can create a Class with a string and an int variable, and create a params array for the class. But I'd rather not, since it would involve constructing a new Class for each set
Why not using a class
public class PrintParameter
{
public int Count {get;set;}
public string Content{get;set;}
}
Then
public void PrintTimes(List<PrintParameter> inputs)
{
//for each input print the "Content", "Count" times
}
Or
public void PrintTimes(params PrintParameter[] inputs)
{
//for each input print the "Content", "Count" times
}
If you don't want to define a class you may try something like List<KeyValuePair<string,int>> or other alternatives such as List<Tuple<string,int>> and etc. However the preferred way of doing is to use a class with meaningful properties.
How about just dropping the params keyword and taking arrays instead? That is, make the signature PrintTimes(string[], int[]). PrintTimes(new[]{"A","B","C","D"}, new[]{2,1,3,2}); isn't that much more to write.
There are several ways you can go about solving this problem. While you can only have one params, you can just make both your parameters arrays:
PrintTimes(string[] strings, int[] printCounts)
{
// Assert strings.Length == printCounts.Length
for (int i = 0; i < strings.Length; i++)
{
for (int j = 0; j < printCounts[i]; j++)
{
// Print strings[i]
}
}
}
Then it can be called like this:
int[] numbers = new int[3] {1, 2, 3};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
PrintTimes(names, numbers);
Following up on Hossein's suggestion, why not something as simple as:
void PrintTimes(List<String> strings, List<Int> count)
(or do it as an array as the comments said) Then inside PrintTimes require the inputs to be the same length or some logical fail when they don't.

Can an Action/delegate change it's arguments value?

I ran into what was to me an unexpected result when testing a simple ForEach extension method.
ForEach method
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null) throw new ArgumentNullException("action");
foreach (T element in list)
{
action(element);
}
}
Test method
[TestMethod]
public void BasicForEachTest()
{
int[] numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.ForEach(num =>
{
num = 0;
});
Assert.AreEqual(0, numbers.Sum());
}
Why would numbers.Sum() be equal to 55 and not 0?
num is the copy of the value of the current element you are iterating over. So you are just changing the copy.
What you do is basically this:
foreach(int num in numbers)
{
num = 0;
}
Surely you do not expect this to change the content of the array?
Edit: What you want is this:
for (int i in numbers.Length)
{
numbers[i] = 0;
}
In your specific case you could maintain an index in your ForEach extension method and pass that as second argument to the action and then use it like this:
numbers.ForEachWithIndex((num, index) => numbers[index] = 0);
However in general: Creating Linq style extension methods which modify the collection they are applied to are bad style (IMO). If you write an extension method which cannot be applied to an IEnumerable<T> you should really think hard about it if you really need it (especially when you write with the intention of modifying the collection). You have not much to gain but much to loose (like unexpected side effects). I'm sure there are exceptions but I stick to that rule and it has served me well.
Because num is a copy.
It's as if you were doing this:
int i = numbers[0];
i = 0;
You wouldn't expect that to change numbers[0], would you?
Because int is a value type and is passed to your extension method as a value parameter. Thus a copy of numbers is passed to your ForEach method. The values stored in the numbers array that is initialized in the BasicForEachTest method are never modified.
Check this article by Jon Skeet to read more on value types and value parameters.
I am not claiming that the code in this answer is useful, but (it works and) I think it illustrates what you need in order to make your approach work. The argument must be marked ref. The BCL does not have a delegate type with ref, so just write your own (not inside any class):
public delegate void MyActionRef<T>(ref T arg);
With that, your method becomes:
public static void ForEach2<T>(this T[] list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Length; idx++)
{
actionRef(ref list[idx]);
}
}
Now, remember to use the ref keyword in your test method:
numbers.ForEach2((ref int num) =>
{
num = 0;
});
This works because it is OK to pass an array entry ByRef (ref).
If you want to extend IList<> instead, you have to do:
public static void ForEach3<T>(this IList<T> list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Count; idx++)
{
var temp = list[idx];
actionRef(ref temp);
list[idx] = temp;
}
}
Hope this helps your understanding.
Note: I had to use for loops. In C#, in foreach (var x in Yyyy) { /* ... */ }, it is not allowed to assign to x (which includes passing x ByRef (with ref or out)) inside the loop body.

How to make a sortedlist sort reversely? Do I have to customize a IComparer?

In a sortedlist queue, queue.value[0] gives the corresponding value of a min key. what if i would like to make that it gives the value of a max key?
Do i have to rewrite the icomparer?
Yes you have to rewrite the comparer
example for string as key: (just exchanged x.CompareTo(y) with y.CompareTo(x) )
private class InvertedComparer : IComparer<String>
{
public int Compare(string x, string y)
{
return y.CompareTo(x);
}
}
and the call:
SortedList<string, Object> list = new SortedList<string, Object>(new InvertedComparer());
Here's a link to an article that implements a ReversibleSortedList. This allows for changing the sort direction.
In case you always want reversed sort behavior without the ability to change it on demand, I'd try the constructor that accepts an IComparer.
Just use Array.Reverse() in some simple cases.
using System;
class Program
{
static void Main()
{
// Input array.
int[] array = { 1, 2, 3 };
// Print.
foreach (int value in array)
{
Console.WriteLine(value);
}
Console.WriteLine();
// Reverse.
Array.Reverse(array);
// Print.
foreach (int value in array)
{
Console.WriteLine(value);
}
Console.WriteLine();
// Reverse again.
Array.Reverse(array);
// Print.
foreach (int value in array)
{
Console.WriteLine(value);
}
}
}
* Output *
1
2
3
3
2
1
1
2
3
You could just invert any existing IComparers. Something like:
public static IComparer<T> Invert<T>(this IComparer<T> comparer)
{
return Comparer<T>.Create((x, y) => comparer.Compare(y, x));
}
And use your regular comparer. For e.g.
new SortedList<,>(myShinyComparer.Invert());

Search for a string in Enum and return the Enum

I have an enumeration:
public enum MyColours
{
Red,
Green,
Blue,
Yellow,
Fuchsia,
Aqua,
Orange
}
and I have a string:
string colour = "Red";
I want to be able to return:
MyColours.Red
from:
public MyColours GetColour(string colour)
So far i have:
public MyColours GetColours(string colour)
{
string[] colours = Enum.GetNames(typeof(MyColours));
int[] values = Enum.GetValues(typeof(MyColours));
int i;
for(int i = 0; i < colours.Length; i++)
{
if(colour.Equals(colours[i], StringComparison.Ordinal)
break;
}
int value = values[i];
// I know all the information about the matched enumeration
// but how do i convert this information into returning a
// MyColour enumeration?
}
As you can see, I'm a bit stuck. Is there anyway to select an enumerator by value. Something like:
MyColour(2)
would result in
MyColour.Green
check out System.Enum.Parse:
enum Colors {Red, Green, Blue}
// your code:
Colors color = (Colors)System.Enum.Parse(typeof(Colors), "Green");
You can cast the int to an enum
(MyColour)2
There is also the option of Enum.Parse
(MyColour)Enum.Parse(typeof(MyColour), "Red")
Given the latest and greatest changes to .NET (+ Core) and C# 7, here is the best solution:
var ignoreCase = true;
Enum.TryParse("red", ignoreCase , out MyColours colour);
colour variable can be used within the scope of Enum.TryParse
All you need is Enum.Parse.
var color = Enum.Parse<Colors>("Green");
I marked OregonGhost's answer +1, then I tried to use the iteration and realised it wasn't quite right because Enum.GetNames returns strings. You want Enum.GetValues:
public MyColours GetColours(string colour)
{
foreach (MyColours mc in Enum.GetValues(typeof(MyColours)))
if (mc.ToString() == surveySystem)
return mc;
return MyColors.Default;
}
You can use Enum.Parse to get an enum value from the name. You can iterate over all values with Enum.GetNames, and you can just cast an int to an enum to get the enum value from the int value.
Like this, for example:
public MyColours GetColours(string colour)
{
foreach (MyColours mc in Enum.GetNames(typeof(MyColours))) {
if (mc.ToString().Contains(colour)) {
return mc;
}
}
return MyColours.Red; // Default value
}
or:
public MyColours GetColours(string colour)
{
return (MyColours)Enum.Parse(typeof(MyColours), colour, true); // true = ignoreCase
}
The latter will throw an ArgumentException if the value is not found, you may want to catch it inside the function and return the default value.
Try this method.
public static class Helper
{
public static T FromStr<T>(string str) where T : struct, System.Enum
=> System.Enum.TryParse<T>(value:str,ignoreCase:true,result:out var result)
? result
: default;
public static T? FromStrNull<T>(string str) where T : struct, System.Enum
=> System.Enum.TryParse<T>(value: str,ignoreCase: true,result: out var result)
? result
: null;
}
And use it like this
var color = Helper.FromStr<MyColours>("red");
As mentioned in previous answers, you can cast directly to the underlying datatype (int -> enum type) or parse (string -> enum type).
but beware - there is no .TryParse for enums, so you WILL need a try/catch block around the parse to catch failures.
class EnumStringToInt // to search for a string in enum
{
enum Numbers{one,two,hree};
static void Main()
{
Numbers num = Numbers.one; // converting enum to string
string str = num.ToString();
//Console.WriteLine(str);
string str1 = "four";
string[] getnames = (string[])Enum.GetNames(typeof(Numbers));
int[] getnum = (int[])Enum.GetValues(typeof(Numbers));
try
{
for (int i = 0; i <= getnum.Length; i++)
{
if (str1.Equals(getnames[i]))
{
Numbers num1 = (Numbers)Enum.Parse(typeof(Numbers), str1);
Console.WriteLine("string found:{0}", num1);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Value not found!", ex);
}
}
}
One thing that might be useful to you (besides the already valid/good answers provided so far) is the StringEnum idea provided here
With this you can define your enumerations as classes (the examples are in vb.net):
< StringEnumRegisteredOnly(), DebuggerStepThrough(),
ImmutableObject(True)> Public NotInheritable Class
eAuthenticationMethod Inherits StringEnumBase(Of
eAuthenticationMethod)
Private Sub New(ByVal StrValue As String)
MyBase.New(StrValue)
End Sub
< Description("Use User Password Authentication")> Public Shared ReadOnly UsernamePassword As New eAuthenticationMethod("UP")
< Description("Use Windows Authentication")> Public Shared ReadOnly WindowsAuthentication As New eAuthenticationMethod("W")
End Class
And now you could use the this class as you would use an enum: eAuthenticationMethod.WindowsAuthentication and this would be essentially like assigning the 'W' the logical value of WindowsAuthentication (inside the enum) and if you were to view this value from a properties window (or something else that uses the System.ComponentModel.Description property) you would get "Use Windows Authentication".
I've been using this for a long time now and it makes the code more clear in intent.
(MyColours)Enum.Parse(typeof(MyColours), "red", true); // MyColours.Red
(int)((MyColours)Enum.Parse(typeof(MyColours), "red", true)); // 0
You might also want to check out some of the suggestions in this blog post:
My new little friend, Enum<T>
The post describes a way to create a very simple generic helper class which enables you to avoid the ugly casting syntax inherent with Enum.Parse - instead you end up writing something like this in your code:
MyColours colour = Enum<MyColours>.Parse(stringValue);
Or check out some of the comments in the same post which talk about using an extension method to achieve similar.

Populating a list of integers in .NET

I need a list of integers from 1 to x where x is set by the user. I could build it with a for loop eg assuming x is an integer set previously:
List<int> iList = new List<int>();
for (int i = 1; i <= x; i++)
{
iList.Add(i);
}
This seems dumb, surely there's a more elegant way to do this, something like the PHP range method
If you're using .Net 3.5, Enumerable.Range is what you need.
Generates a sequence of integral
numbers within a specified range.
LINQ to the rescue:
// Adding value to existing list
var list = new List<int>();
list.AddRange(Enumerable.Range(1, x));
// Creating new list
var list = Enumerable.Range(1, x).ToList();
See Generation Operators on LINQ 101
I'm one of many who has blogged about a ruby-esque To extension method that you can write if you're using C#3.0:
public static class IntegerExtensions
{
public static IEnumerable<int> To(this int first, int last)
{
for (int i = first; i <= last; i++)
{
yield return i;
}
}
}
Then you can create your list of integers like this
List<int> = first.To(last).ToList();
or
List<int> = 1.To(x).ToList();
Here is a short method that returns a List of integers.
public static List<int> MakeSequence(int startingValue, int sequenceLength)
{
return Enumerable.Range(startingValue, sequenceLength).ToList<int>();
}

Categories