I'd like to create a generic method for converting any System.Enum derived type to its corresponding integer value, without casting and preferably without parsing a string.
Eg, what I want is something like this:
// Trivial example, not actually what I'm doing.
class Converter
{
int ToInteger(System.Enum anEnum)
{
(int)anEnum;
}
}
But this doesn't appear to work. Resharper reports that you can not cast expression of type 'System.Enum' to type 'int'.
Now I've come up with this solution but I'd rather have something more efficient.
class Converter
{
int ToInteger(System.Enum anEnum)
{
return int.Parse(anEnum.ToString("d"));
}
}
Any suggestions?
If you don't want to cast,
Convert.ToInt32()
could do the trick.
The direct cast (via (int)enumValue) is not possible. Note that this would also be "dangerous" since an enum can have different underlying types (int, long, byte...).
More formally: System.Enum has no direct inheritance relationship with Int32 (though both are ValueTypes), so the explicit cast cannot be correct within the type system
I got it to work by casting to an object and then to an int:
public static class EnumExtensions
{
public static int ToInt(this Enum enumValue)
{
return (int)((object)enumValue);
}
}
This is ugly and probably not the best way. I'll keep messing with it, to see if I can come up with something better....
EDIT: Was just about to post that Convert.ToInt32(enumValue) works as well, and noticed that MartinStettner beat me to it.
public static class EnumExtensions
{
public static int ToInt(this Enum enumValue)
{
return Convert.ToInt32(enumValue);
}
}
Test:
int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday
EDIT 2: In the comments, someone said that this only works in C# 3.0. I just tested this in VS2005 like this and it worked:
public static class Helpers
{
public static int ToInt(Enum enumValue)
{
return Convert.ToInt32(enumValue);
}
}
static void Main(string[] args)
{
Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
}
If you need to convert any enum to its underlying type (not all enums are backed by int) then you can use:
return System.Convert.ChangeType(
enumValue,
Enum.GetUnderlyingType(enumValue.GetType()));
Why do you need to reinvent the wheel with a helper method? It's perfectly legal to cast an enum value to its underlying type.
It's less typing, and in my opinion more readable, to use...
int x = (int)DayOfWeek.Tuesday;
...rather than something like...
int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();
From my answer here:
Given e as in:
Enum e = Question.Role;
Then these work:
int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);
The last two are plain ugly. The first one should be more readable, though the second one is much faster. Or may be an extension method is the best, best of both worlds.
public static int GetIntValue(this Enum e)
{
return e.GetValue<int>();
}
public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
return (T)(object)e;
}
Now you can call:
e.GetValue<int>(); //or
e.GetIntValue();
Casting from a System.Enum to an int works fine for me (it's also on the MSDN). Perhaps it's a Resharper bug.
Since Enums are restricted to byte, sbyte, short, ushort, int, uint, long and ulong, we can make some assumptions.
We can avoid exceptions during conversion by using the largest available container. Unfortunately, which container to use is not clear because ulong will blow up for negative numbers and long will blow up for numbers between long.MaxValue and ulong.MaxValue. We need to switch between these choices based on the underlying type.
Of course, you still need to decide what to do when the result doesn't fit inside an int. I think casting is okay, but there are still some gotchas:
for enums based on a type with a field space larger than int (long and ulong), it's possible some enums will evaluate to the same value.
casting a number larger than int.MaxValue will throw an exception if you are in a checked region.
Here's my suggestion, I'll leave it to the reader to decide where to expose this function; as a helper or an extension.
public int ToInt(Enum e)
{
unchecked
{
if (e.GetTypeCode() == TypeCode.UInt64)
return (int)Convert.ToUInt64(e);
else
return (int)Convert.ToInt64(e);
}
}
If you read the code for Convert.ToInt32, you can see that it casts the Enum to IConvertible, then calls ToInt32(null).
Don't forget that the Enum type itself has a bunch of static helper functions in it. If all you want to do is convert an instance of the enum to its corresponding integer type, then casting is probably the most efficient way.
I think ReSharper is complaining because Enum isn't an enumeration of any particular type, and enumerations themselves derive from a scalar valuetype, not Enum. If you need adaptable casting in a generic way, I would say this could suite you well (note that the enumeration type itself is also included in the generic:
public static EnumHelpers
{
public static T Convert<T, E>(E enumValue)
{
return (T)enumValue;
}
}
This could then be used like so:
public enum StopLight: int
{
Red = 1,
Yellow = 2,
Green = 3
}
// ...
int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);
I can't say for sure off the top of my head, but the above code might even be supported by C#'s type inference, allowing the following:
int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);
Related
In enum.cs there are two implementation of enum.IsDefined, the first one I always use is IsDefined(Type enumType, object value) works perfectly fine
But there is an other IsDefined, this one :
public static bool IsDefined<TEnum>(TEnum value) where TEnum : struct, Enum
{
RuntimeType enumType = (RuntimeType)typeof(TEnum);
ulong[] ulValues = Enum.InternalGetValues(enumType);
ulong ulValue = Enum.ToUInt64(value);
return Array.BinarySearch(ulValues, ulValue) >= 0;
}
source : Enum.cs
Is there any way this method could return false ?
It looks like a bug to me, this function should accept an Enum in parameter, not a TEnum. Or am I completely missing the point here ?
I would expect this function to work just like the overload, just being a synthaxic sugar
Thanks to Etienne de Martel
Yes it can return false, the idea is to cast before checking if the value is defined :
using System;
public enum E
{
V = 0
}
public class Program
{
public static void Main()
{
E e = (E)1;
Console.WriteLine(Enum.IsDefined(e));
}
}
The version that accepts object is OK, but it forces a "boxing" operation, i.e. it forces a heap allocation. In isolation, affordable, but: allocations add up. At the time, .NET didn't have generics, so: it was the best that could be done.
Generics serves as a mitigation against boxing (for value-types), so here it is used to avoid that overhead. It also makes calling it easier, since you don't need to specify the type at all in most cases (except perhaps when passing the literal zero). The compiler can infer the generics from the type of the argument.
How can I call a method that expects an int value by using an enum member. I dont want the called method to have to know about the enum.
public enum Volume : int
{
Low = 1,
Medium = 2,
High = 3
}
public void Start() {
DoSomeWork(Volume.Low); //this complains
//this works DoSomething((int)Volume.Low);
}
public void DoSomeWork(int vol) {
//Do something
}
Cast it explicitly to int (as you have already figured out):
DoSomeWork((int)Volume.Low)
Implicit conversion from enum to underlying type is forbidden, since there are a lot of cases when this conversion does not make sense. #EricLippert explains this well enough here.
However why introduce the enum if you are not using it? If the volume rate in your program is specified by the enum - then this is the type your method should expect as a parameter.
Call it like this:
DoSomeWork( (int) Volume.Low );
Why not using this way:
public void DoSomeWork(Volume volume) {
//Do something
}
as documentation states
Every enumeration type has an underlying type, which can be any integral type except char. The default underlying type of the enumeration elements is int.
so you can just simple cast it to int and pass it to the method that way.
DoSomeWork((int)Volume.Low);
I know that I can convert an int to an enum using a cast
MyEnumType myEnum = (MyEnumType) myInteger;
The problem here is that the runtime cast won't stop me at build time if myInteger is not of type int
void MyMethod(MyObject myObject)
{
MyEnumType myEnum = (MyEnumType) myObject.someProperty;
....
}
The above is not an uncommon code pattern but it won't protect me at build-time if the object's property type has been changed.
Is there a built-in method to do this conversion that will give me a build-time error? I could, of course, write a generic method rather easily but I'm wondering if one is built in.
You can use
Enum.TryParse(myInteger.ToString(), out result)
to get the Enum value of an int.
Hope this helps,
You can create a method to do this for your one enum easily enough:
public static MyEnumType CastFromInt<T>(int n)
{
return (MyEnumType)n;
}
Sadly, because there is no way to apply a generic constraint such that a generic type argument is an enumeration, there's no good way to genericize this. You could write something like this:
public static T CastFromInt<T>(int n)
{
return (T)(object)n;
}
but that assumes the caller uses an enum as the type of T. If they don't, it has problems. This also needlessly boxes the integer.
My question concerns type-checking in a chain of generic methods. Let's say I have an extension method that attempts to convert a byte array to an int, decimal, string, or DateTime.
public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible
{
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
var magic = FromString<T>(s);
return (T)Convert.ChangeType(magic, typeof(T));
}
This calls a method called FromString that translates the concatenated string to a specific type. Unfortunately, the business logic is completely dependent on the type T. So I end up with a megalithic if-else block:
private static T FromString<T>(string s) where T : struct
{
if (typeof(T).Equals(typeof(decimal)))
{
var x = (decimal)System.Convert.ToInt32(s) / 100;
return (T)Convert.ChangeType(x, typeof(T));
}
if (typeof(T).Equals(typeof(int)))
{
var x = System.Convert.ToInt32(s);
return (T)Convert.ChangeType(x, typeof(T));
}
if (typeof(T).Equals(typeof(DateTime)))
... etc ...
}
At this point, I would prefer multiple methods with the same name and different return types, something along the lines of this:
// <WishfulThinking>
private static decimal FromString<T>(string s)
{
return (decimal)System.Convert.ToInt32(s) / 100;
}
private static int FromString<T>(string s)
{
return System.Convert.ToInt32(s);
}
// </WishfulThinking>
... but I realize this is not valid, as T can't be constrained to a specific type, and without it, all of the methods will have the same conflicting signature.
Is there a feasible way to implement FromString without the excessive type-checking? Or might there be a better way to approach this problem altogether?
Or might there be a better way to approach this problem altogether?
Sure, there is one: you can make each converter into a lambda, make a dictionary of them, and use them for the conversion, like this:
private static IDictionary<Type,Func<string,object>> Converters = new Dictionary<Type,Func<string,object>> {
{typeof(int), s => Convert.ChangeType(System.Convert.ToInt32(s), typeof(int))}
, {typeof(decimal), s => Convert.ChangeType((decimal)System.Convert.ToInt32(s) / 100, typeof(decimal))}
, ... // And so on
};
public static T Read<T>(this ByteContainer ba, int size, string format) where T : struct, IConvertible {
Func<string,object> converter;
if (!Converters.TryGetValue(typeof(T), out converter)) {
throw new ArgumentException("Unsupported type: "+typeof(T));
}
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
return (T)converter(s);
}
In general, if you have to write logic that must always check the type of a generic type parameter, you are not actually writing code that benefits from being generic. That being the case, and assuming the actual problem you're trying to solve is the need to convert a byte array into some predictable built-in type that it represents, I recommend you abandon this approach and use the methods in the BitConverter class.
At the point where you could determine the value of T, simply call the appropriate method on the BitConverter class.
Update: If a generic solution is necessary, I'd suggest something similar to dasblinkenlight's answer, though I would let the caller inject the converter (after all, the caller knows the requisite result type), which avoids the problem of maintaining a list of conversion functions alongside the generic method:
public static T Read<T>(this ByteContainer ba, int size, string format,
Func<string, T> converter) where T : struct, IConvertible
{
var s = string.Concat(ba.Bytes.Select(b => b.ToString(format)).ToArray());
return converter(s);
}
Say I want to have a method that takes any kind of number, is there a base class (or some other concept) that I can use?
As far as I know I have to make overloads for all the different numeric types (Int32, Int16, Byte, UInt32, Double, Float, Decimal, etc). This seems awfully tedious. Either that or use the type object and throw exceptions if they are not convertible or assignable to a double - which is pretty bad as it means no compile time checking.
UPDATE:
OK thanks for the comments, you are right Scarecrow and Marc, in fact declaring it as Double actually works for all except Decimal.
So the answer I was looking for is Double - it acts like a base class here since most numeric types are assignable to it. (I guess Decimal is not assignable to Double, as it could get too big.)
public void TestFormatDollars() {
int i = 5;
string str = FormatDollars(i); // this is OK
byte b = 5;
str = FormatDollars(b); // this is OK
decimal d = 5;
str = FormatDollars(d); // this does not compile - decimal is not assignable to double
}
public static string FormatDollars(double num) {
return "$" + num;
}
The answer is: you don't need to provide overloads for ALL the numeric types, just for Double and Decimal. All others (except maybe some very unusually large ones) will be automatically converted to these.
Not a base class but in fact that was the red herring. The base class System.ValueType doesn't help much as it includes types that are not numerics. The language reference i was reading was what got me confused in the first place :)
(I was just looking for who to attribute the answer to and it was a combination of Scarecrow and Marc Gravell, but since they were comments i have put the answer here)
There isn't one (or at least, not one that just means "numbers"). You could use:
void Foo<T>(T value) where T : struct {...}
But that allows any struct - not just numbers. If you want to do arithmetic, generic operators may be of use. Other than that; overloads it the most viable option.
What I do:
public interface INumeric<T>
{
T Zero { get; }
T One { get; }
T MaxValue { get; }
T MinValue { get; }
T Add(T a, T b);
// T Substract(....
// T Mult...
}
public struct Numeric:
INumeric<int>,
INumeric<float>,
INumeric<byte>,
INumeric<decimal>,
// INumeric<other types>
{
int INumeric<int>.Zero => 0;
int INumeric<int>.One => 1;
int INumeric<int>.MinValue => int.MinValue;
int INumeric<int>.MaxValue => int.MaxValue;
int INumeric<int>.Add(int x, int y) => x + y;
// other implementations...
}
Now, you can use it in a method:
bool IsZero<TNum, T>(TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
or extension method
public static bool IsZero<TNum, T>(this TNum ops, T number)
where TNum : INumeric<T>
{
return number == ops.Zero;
}
and in your code:
...
var n = new Numeric(); // can be an static prop
Console.WriteLine(IsZero(n, 5)); // false
Console.WriteLine(IsZero(n, 0f)); // true
Console.WriteLine(IsZero(n, "0")); // compiler error
or, with extension method:
Console.WriteLine(n.IsZero(5)); // false
Console.WriteLine(n.IsZero(0f)); // true
Console.WriteLine(n.IsZero("0")); // compiler error
The short answer is: Numeric types are value types, hence they derive from System.ValueType.
The full answer is: you should read this article from MSDN. Moreover I think that you should read C# language reference :). Value type not equals numeric type, because values types include also structures and enumerations.
The base class of the numeric types is ValueType.
Unfortunately that still won't help you: DateTime, bool, Enum and hundreds of other types also derive from ValueType. There's no NumericType base class in .NET.
In .NET 7 a new API for generic math was finally introduced.
.NET 7 introduces new math-related generic interfaces to the base class library. The availability of these interfaces means you can constrain a type parameter of a generic type or method to be "number-like".
It features the INumber<T> interface that is now implemented by all numeric types, so you can do this:
public static string FormatDollars<T>(T num) where T : INumber<T>
{
return "$" + num;
}
It also provides fine-grained numeric interfaces to identify type categories, e.g.:
IBinaryInteger<T> for Byte (byte), Int16 (short), Int32 (int), Int64 (long), ...
IFloatingPoint<T> for Double (double), decimal (Decimal), ...
...
For operators it offers a variety of operator interfaces that are implemented by all numeric types.
IAdditionOperators<TSelf,TOther,TResult> for plus (+).
IMultiplyOperators<TSelf,TOther,TResult> for multiply (*).
...
I assume that your question was not explicitly about value types but numeric types. However, if you need generic type constraints that enforce value types as well, specify both.
public static string FormatDollars<T>(T num) where T : struct, INumber<T>
{
return "$" + num;
}
Are overloaded method signitures out of the question here?
If you want a constrained group of methods to performe the same task you could voerload the public method and call a private method that takes any number via casting the input to a double.