C# int to enum conversion [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Cast int to enum in C#
If I have the following code:
enum foo : int
{
option1 = 1,
option2,
...
}
private foo convertIntToFoo(int value)
{
// Convert int to respective Foo value or throw exception
}
What would the conversion code look like?

It's fine just to cast your int to Foo:
int i = 1;
Foo f = (Foo)i;
If you try to cast a value that's not defined it will still work. The only harm that may come from this is in how you use the value later on.
If you really want to make sure your value is defined in the enum, you can use Enum.IsDefined:
int i = 1;
if (Enum.IsDefined(typeof(Foo), i))
{
Foo f = (Foo)i;
}
else
{
// Throw exception, etc.
}
However, using IsDefined costs more than just casting. Which you use depends on your implemenation. You might consider restricting user input, or handling a default case when you use the enum.
Also note that you don't have to specify that your enum inherits from int; this is the default behavior.

I'm pretty sure you can do explicit casting here.
foo f = (foo)value;
So long as you say the enum inherits(?) from int, which you have.
enum foo : int
EDIT Yes it turns out that by default, an enums underlying type is int. You can however use any integral type except char.
You can also cast from a value that's not in the enum, producing an invalid enum. I suspect this works by just changing the type of the reference and not actually changing the value in memory.
enum (C# Reference)
Enumeration Types (C# Programming Guide)

Casting should be enough. If you're using C# 3.0 you can make a handy extension method to parse enum values:
public static TEnum ToEnum<TInput, TEnum>(this TInput value)
{
Type type = typeof(TEnum);
if (value == default(TInput))
{
throw new ArgumentException("Value is null or empty.", "value");
}
if (!type.IsEnum)
{
throw new ArgumentException("Enum expected.", "TEnum");
}
return (TEnum)Enum.Parse(type, value.ToString(), true);
}

if (Enum.IsDefined(typeof(foo), value))
{
return (Foo)Enum.Parse(typeof(foo), value);
}
Hope this helps
Edit
This answer got down voted as value in my example is a string, where as the question asked for an int. My applogies; the following should be a bit clearer :-)
Type fooType = typeof(foo);
if (Enum.IsDefined(fooType , value.ToString()))
{
return (Foo)Enum.Parse(fooType , value.ToString());
}

You don't need the inheritance. You can do:
(Foo)1
it will work ;)

Related

Retrieving integer values from an enum

I have defined an enum and tried to retrieve it as follows
class Demo
{
enum hello
{
one=1,
two
}
public static void Main()
{
Console.WriteLine(hello.one);
Console.ReadLine();
}
}
Now, how do i retrieve the integer value "1" from the enum ?
There's an explicit conversion from any enum type to its underlying type (int in this case). So:
Console.WriteLine((int) hello.one);
Likewise there's an explicit conversion the other way:
Console.WriteLine((hello) 1); // Prints "one"
(As a side note, I'd strongly advise you to follow .NET naming conventions, even when writing tiny test apps.)
you can cast the enums like
int a = (int)hello.one
Well you can do a cast to int
Console.WriteLine((int)hello.one);
Try This.
Console.Writeline((int)hello.Value);
or
int value = Convert.ToInt32(hello.one);

How can I tell the compiler that my generics will definitely allow "|=" or casting to int?

I'm bone new to generics in C#, and I'm attempting to create a method that will use generics. I tripped across the where keyword when attempting to create a local variable, so I'm sure that it will be part of the solution.
The reason for this is I have several different enum variables but the method would do the same to each (given a string that is one of the enum's defined values, toggle it on, using the enum like a bit field).
I have most of this together, the part I'm now stuck at is being able to tell the generic method it's ok to allow "|=" as I'm certain any type passed in will support the operator.
I would like to be able to maintain generality, if possible, so could either be an enum or a List and I would execute different code paths depending on the type.
Example of what I'm taking about
enum someType { value1 = 1<<0, value2 = 1<<1, value3 = 1<<2 }; // and so on
// some more enums
private T someMethod<T>(string myIdentifyers)
where T: new()
{
// suppose myIdentifiers is 1 more more of the valid enum options
// assume that the correct strings and enum combinations will be passed
T retval = new T();
while () {
// assume a loop with a method call that parses off one identifyer at a time
// if I have to convert the enum to an int first, so be it, but
// at this point I can't tell it that a cast to int exists
retval |= (T)System.Enum.Parse( typeof(T), oneIdentifyer, false );
}
return retval;
}
I would try something like this (pseudocode):
[Flags]
enum someType { value1 = 1<<0, value2 = 1<<1, value3 = 1<<2 }; // and so on
// some more enums
private T someMethod<T>(string myIdentifyers)
where T: struct, new()
{
// check if enum
if (typeof(T).BaseType != typeof(Enum)) // we should probably check for the flags attribute too
throw new Exception();
// suppose myIdentifiers is 1 more more of the valid enum options
// assume that the correct strings and enum combinations will be passed
int retval = 0;
while () {
// assume a loop with a method call that parses off one identifyer at a time
// if I have to convert the enum to an int first, so be it, but
// at this point I can't tell it that a cast to int exists
retval |= (int) (object) System.Enum.Parse( typeof(T), oneIdentifyer, false );
}
return (T) (object) retval;
}
It's not possible to express enum generic-constraints as of C# 4. Nor is it possible to express operator-constraints.
That said, I think you're looking for a method like this:
public static T AssembleFlagsEnum<T>(IEnumerable<string> names) where T : struct
{
return (T)(object)names.Aggregate(0,
(valSoFar, name) => valSoFar | Convert.ToInt32(Enum.Parse(typeof(T), name)));
}
Note that this doesn't validate that the type is a [Flags] enum. Nor will it work for enums which have underlying-types other than int.
In general, there's no good way to invoke operators on a generic type, although there are some kludges and workarounds that can help out in some circumstances.
See this similar question: Generic C# Code and the Plus Operator
In this case, since you know your enums cast to and from int, I think Bruno's method is the way to go.
Unfortunately it's not possible.
You can restrict with the struct constraint to say value type but obviously that includes more than integers. The only thing you could then do is early in the code to check on the actual type.
Supported constraint restrictions are described at http://msdn.microsoft.com/en-us/library/d5x73970.aspx
You can't do operator constraints - see Solution for overloaded operator constraint in .NET generics

How to check whether a (generic) number type is an integral or nonintegral type in C#?

I've got a generic type T. Using Marc's Operator class I can perform calculations on it.
Is it possible to detect by mere calculations whether the type is an integral or a nonintegral type?
Perhaps there is a better solution? I'd prefer to support any possible type, so I'd like to prevent hard-coding which types are integral/nonintegral.
Background info
The situation I find myself in is I want to cast a double to T but round to the nearest value of T to the double value.
int a = (int)2.6 results in 2 while I want it to result it in 3, without knowing the type (in this case int). It could also be double, in which case I want the outcome to be 2.6.
Have you tried Convert.ChangeType? Something like:
Convert.ChangeType(1.9d, typeof (T))
It will work for all numeric types I think (as long as the first parameter is iConvertible and the type is a supported one which all basic numerics should be I believe).
Its important to mention that this will call something like double.ToInt32 which rounds values rather than truncates (bankers rounding I believe).
I tested this in a little LinqPad program and it does what I think you want:
void Main()
{
var foo = RetNum<decimal>();
foo.Dump();
}
public static T RetNum<T>()
{
return (T)Convert.ChangeType(1.9d, typeof (T));
}
Here's a method which will determine if a particular value stored in a generic numeric type is an integer without hardcoding. Tested working for me on .NET 4. Correctly handles all built in numeric types (as defined in the MSDN link at the bottom) except BigInteger, which doesn't implement IConvertible.
public static bool? IsInteger<T>(T testNumber) where T : IConvertible
{
// returns null if T is non-numeric
bool? isInt = null;
try
{
isInt = testNumber.ToUInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch (OverflowException)
{
// casting a negative int will cause this exception
try
{
isInt = testNumber.ToInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch
{
// throw depending on desired behavior
}
}
catch
{
// throw depending on desired behavior
}
return isInt;
}
Here's a method which will determine whether a particular type is an integral type.
public static bool? IsIntegerType<T>() where T : IConvertible
{
bool? isInt = null;
try
{
isInt = Math.Round((double)Convert.ChangeType((T)Convert.ChangeType(0.1d, typeof(T)),typeof(double)), 1) != .1d;
// if you don't round it and T is float you'll get the wrong result
}
catch
{
// T is a non numeric type, or something went wrong with the activator
}
return isInt;
}
Convert.ChangeType is the way to convert, with rounding, between two generic numeric types. But for kicks and curiosity, here's a way to convert a generic numeric type to an int, which could be extended to return a generic type without too much difficulty.
public static int GetInt32<T>(T target) where T : IConvertible
{
bool? isInt = IsInteger<T>(target);
if (isInt == null) throw new ArgumentException(); // put an appropriate message in
else if (isInt == true)
{
try
{
int i = target.ToInt32(CultureInfo.InvariantCulture);
return i;
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
else
{
try
{
double d = target.ToDouble(CultureInfo.InvariantCulture);
return (int)Math.Round(d);
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
}
My results:
double d = 1.9;
byte b = 1;
sbyte sb = 1;
float f = 2.0f;
short s = 1;
int i = -3;
UInt16 ui = 44;
ulong ul = ulong.MaxValue;
bool? dd = IsInteger<double>(d); // false
bool? dt = IsInteger<DateTime>(DateTime.Now); // null
bool? db = IsInteger<byte>(b); // true
bool? dsb = IsInteger<sbyte>(sb); // true
bool? df = IsInteger<float>(f); // true
bool? ds = IsInteger<short>(s); // true
bool? di = IsInteger<int>(i); // true
bool? dui = IsInteger<UInt16>(ui); // true
bool? dul = IsInteger<ulong>(ul); // true
int converted = GetInt32<double>(d); // coverted==2
bool? isd = IsIntegerType<double>(); // false
bool? isi = IsIntegerType<int>(); // true
Additionally, this MSDN page has some example code which might be helpful. Specifically, it includes a list of types considered to be numeric.
I'm not 100% sure what you're asking, but:
To check if it's an integral type, use this: if (obj is float || obj is double), or if typeof(T) == typeof(float) || typeof(T) == typeof(double))
To check if it's an integral value, cast it to a double, and then do if(value == Math.Round(value))
Of course, that is assuming that you have a number in the first place. I believe that the Operator class you're using supports things like DateTime. Would it be better to make your generic method have a generic constraint where T : IConvertible? That way there'd be explicit ToDouble and ToInteger methods.
Edit:
I think I understand: you've got two local variables, double d; T num;. You want to cast d to type T, but with proper rounding if T is a integral type. Is that correct?
Assuming that's correct, here's what I'd do:
public void SomeMethod<T>()
{
double d;
// I think I got all the floating-point types. There's only a few, so we can test for them explicitly.
if(typeof(T) != typeof(double) && typeof(T) != typeof(float) && typeof(T) != typeof(Decimal))
{
d = Math.Round(d);
}
T converted = Convert.ChangeType(d, typeof(T));
}
Chris's answer gives a possible solution to the scenario I mentioned, but for performance reasons I am still attempting to answer the actual question.
The assumption (untested) is, Convert.ChangeType is much slower than Math.Round(). Ideally, I can check one time whether the given type is integral or not, and conditionally call Math.Round() from then on to obtain a much more efficient solution than calling Convert.ChangeType() constantly.
I'm attempting the following implementation:
Convert both 3, 2 and 1 to the desired unknown type. (This assumes a conversion from an int to the numeric type is possible, which should always be possible anyhow.)
In case 3 / 2 == 1, it is an integral type. Otherwise, it is a nonintegral type.
This solution doesn't rely anywhere on knowing the type and solely uses conversions and calculations.

Can I cast from a generic type to an enum in C#?

I'm writing an utility function that gets a integer from the database and returns a typed enum to the application.
Here is what I tried to do (note I pass in a data reader and column name instead of the int in my real function):
public static T GetEnum<T>(int enumAsInt)
{
Type enumType = typeof(T);
Enum value = (Enum)Enum.ToObject(enumType, enumAsInt);
if (Enum.IsDefined(enumType, value) == false)
{
throw new NotSupportedException("Unable to convert value from database to the type: " + enumType.ToString());
}
return (T)value;
}
But it won't let me cast (T)value saying:
Cannot convert type 'System.Enum' to 'T'.
Also I've read quite a bit of mixed reviews about using Enum.IsDefined. Performance wise it sounds very poor. How else can I guarantee a valid value?
Like this:
return (T)(object)value;
Change this:
Enum value = (Enum)Enum.ToObject(enumType, enumAsInt);
to this:
T value = (T)Enum.ToObject(enumType, enumAsInt);
and remove the cast :)
For information, using the generic constraint Enum is available from C# 7.3 and greater.

cannot convert type 'string' to 'int?' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion or null type conversion

C# accepts the following:
object o = "hello";
int? i = o as int?;
if (i == null) {
// o was not a boxed int
}
else {
// Can use i.Value to recover the original boxed value
}
But not
String o = "hello";
int? i = o as int?;
if (i == null) {
// o was not a boxed int
}
else {
// Can use i.Value to recover the original boxed value
}
I'm just wondering about the behaviour of the keyword as in C#.
The same as in Java this would fail:
Object test1 = "hello";
Integer test2 = (Integer) test1;
String test3 = "hello";
Integer test4 = (Integer) test3; //compilation error
The compiler knows that a string can never be an int? so it tells you that. That doesn't mean that int? isn't useful. Your attempted use case is far from the normal one. The normal one is "I want to represent an integer and the possibility that the value is missing/unknown". For that, int? works extremely well.
Why would you expect your original code to work? Why would it be helpful?
Note that you can use as with nullable types, for unboxing:
object o = "hello";
int? i = o as int?;
if (i == null)
{
// o was not a boxed int
}
else
{
// Can use i.Value to recover the original boxed value
}
EDIT: Having seen your comment, you don't use as to parse things. You probably want to use int.TryParse:
string text = "123":
int value;
if (int.TryParse(text, out value))
{
Console.WriteLine("Parsed successfully: {0}", value);
}
else
{
Console.WriteLine("Unable to parse text as an integer");
}
If you're sure the string is meant to be an integer (i.e. it's a bug otherwise) then you can just use int.Parse:
int value = int.Parse(text);
That will throw an exception if the parsing fails.
Note also that both of these methods allows you to specify a format provider (usually a culture info) which allows you to express how numbers are expressed in that format (e.g. thousands separators).
EDIT: In answer to your new question, the compiler prevents this because it knows a string can't possibly be a boxed int - the conversion will never ever succeed. When it only knows that the original value is an object, it might succeed.
For instance, suppose I said to you, "Here's a shape: is it a square?" That's a sensible question. It's reasonable to ask it: you can't tell without looking at the shape.
If, however, I said: "Here's a triangle: is it a square?" Then you'd be reasonably entitled to laugh in my face, as a triangle can't possibly be a square - the question doesn't make sense.
int? means a nullable integer type, not an int that could contain any other type of variable.
If you want a variable type that could contain an int or a string, you'd have to use an object, or a string I suppose, and then live a life filled with type casting. I don't know why you would want to do that, though.
int? allows you to store any integer value, or a null value. Which is useful when say the answer to the question "How many orders has this person placed" is legitimately "I don't know" instead of a number of orders, or zero which would be "I know for a fact this person has never placed an order".
I want to add some further information.
An other case, why the cast is invalid and the compiler throws an error on compilation is, that System.String is marked as sealed. So the compiler knows from which types System.String inherites and to which types you can cast the string using the as-operator.
Due to the keyword sealed, the compiler also knows that you cannot inherit from System.String to add functionality or implement some additional interfaces.
The code below is an example and the compiler will throw the following error on compilation
Cannot convert type 'SealedClass' to
'ICastToInterface' via a reference
conversion, boxing conversion,
unboxing conversion, wrapping
conversion, or null type conversion
public class UnsealedClass {
// some code
}
public sealed class SealedClass {
// some code
}
public interface ICastToInterface {
// some code
}
public class Test {
public Test() {
UnsealedClass unsealedClass = new UnsealedClass();
SealedClass sealedClass = new SealedClass();
ICastToInterface unsealedCast = unsealedClass as ICastToInterface; // This works fine
ICastToInterface sealedCast = sealedClass as ICastToInterface; // This won´t compile, cause SealedClass is sealed
}
}
but you can check the value of null and set it to null.
int? blah;
if (blah == null)
{}
int? is a nullable integer, it has nothing to do with casting and the as keyword. "String" is a string type object, which is not convertible to an int (nullable or non-nullable).
The as Keyword is virtually the same as casting using brackets except it will not return an error, it will set the object to null:
int i = 1;
object o = i; //boxing
int j = (int)o; //unboxing
This first example works as the object assigned to o is an int.
Now consider:
string i = "MyString";
object o = MyString;
int j = (int)o //unboxing raises exception
int j = o as int; //raises compilation Error as int is not nullable
int? j = o as int?; /// o == null
I hope that that helps to explain the difference between the two concepts.
Richard

Categories

Resources