Passing enum member to method - c#

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

Related

define a function to accept a specific list parameter

I want to define a function with a parameter, that paramter must be a specific, defined in a list (for example)
i remember doing this years ago but my memory has failed me.
example
public void foo(specific choice list defined in my class){}
specific-list = x,y,z
consume it list this (i think)
foo(myclass.x)
To expand on #kaffekopp's comment, it seems likely that you are talking about an enum, i.e.
public enum MyEnum // declare the enum type (optional: specify an underlying integer type)
{
Apple, // define the choices (note: enums are **not** strictly enforced;
Pear, // they are just named integers, and at runtime you can be surprised to find
Bicycle, // that the actual value is 42, a value you never defined)
}
with (on MyClass):
public MyEnum SomeProp {get;set;} // define a property as being of that enum type
and:
public void Foo(MyEnum option) {...} // define a method that takes a parameter of the type
then either:
Foo(MyEnum.Bicycle); // passing a constant/literal
or:
MyClass obj = ...
Foo(obj.SomeProp); // passing an existing value from somewhere

Is there a typesafe enum conversion from int in c#?

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.

Compiler not calling appropriate generic overload when passed with value type

I have public functions like this:
public static T Get<T>(this Mango m, T defaultValue = default(T)) where T : class
{
//do something; return something;
}
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
Basically I want to individually handle reference types and nullable types. It compiles; until i call for value types. For reference types it compiles.
mango.Get<string>(); // compiles..
mango.Get(""); // compiles..
mango.Get<int>(); // The type 'int' must be a reference type in order to use it as
// parameter 'T' in the generic type or method Get<T>(Mango, T)
//also // The call is ambiguous between the following methods or properties:
// Get<int>(Mango, int) and Get<int>(Mango, int?)
What real ambiguity is here? When T is int, cant it call the struct overload appropriately? Also:
mango.Get<int>(0); // The type 'int' must be a reference type in order to use it as
// parameter 'T' in the generic type or method Get<T>(Mango, T)
Why is the compiler only detecting the reference type overload? I tried having two separate overloads:
public static T Get<T>(this Mango m) where T : class
{
return default(T);
}
public static T? Get<T>(this Mango m) where T : struct
{
return default(T);
}
public static T Get<T>(this Mango m, T def) where T : class
{
return default(T);
}
public static T? Get<T>(this Mango m, T? def) where T : struct
{
return default(T);
}
The problem persisted. And obviously, the first two methods dont compile here since overloading doesn't work merely on the basis of constraints.
I tried by removing the class constrained overload and keeping just the struct constrained one, like this:
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
mango.Get<int>(); // voila compiles!
mango.Get<int>(0); // no problem at all..
// but now I can't have mango.Get<string>() for instance :(
Am I only left with renaming the two functions? I feel its appropriate to have a unified name so that the caller just doesnt have to worry about the implementation detail, but just call Get for any type.
Update: Marc's solution doesnt work if I have to avoid the optional parameter.
mango.Get<int>(); // still wouldnt work!!
But there's more magic :(:(
public static bool IsIt<T>(this T? obj) where T : struct
{
return who knows;
}
public static bool IsIt<T>(this T obj) where T : class
{
return perhaps;
}
By all means I'm expecting the same compiler bug (according to me) to annoy me. But no it works this time.
Guid? g = null;
g.IsIt(); //just fine, and calls the struct constrained overload
"abcd".IsIt(); //just fine, and calls the class constrained overload
So if overload resolution comes before constraint checking as Marc says, shouldn't I get the same error this time too? But no. Why is it so?? What the hell is going on? :x
constraint checking is done after overload resolution, IIRC; the overload resolution seems to prefer the first version. You can force it to use the other, though:
mango.Get<int>((int?)0);
or even:
mango.Get((int?)0);
Personally, I'd probably just change the name to avoid the ambiguity.
Interestingly, the compiler will check the constraints specified within generic types that are used within a method signature, but not for constraints within the signature itself.
Thus, if a method accepted two parameters, one of type T where T : struct along with a Nullable<T>[], the compiler would not consider the method for any T that was not a struct. The method's specified struct constraint for T is not considered in evaluating overloads, but the fact that Nullable<T> constrains T to struct, is.
I really find the total inability to consider constraints in overload evaluation bizarre, given that one could specify a default null value for the Nullable<T>[] parameter, and pretend the parameter didn't exist. The vb.net compilers and C# compilers seem to differ, though, when it comes to what they regard as ambiguous and what they accept.
Let me try to answer myself.
As marc says, constraint checking is done after overload resolution, and between
public static T Get<T>(this Mango m, T defaultValue = default(T)) where T : class
{
//do something; return something;
}
and
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
overload resolution prefers the class version. But that's only when the compiler is given a choice between two similar overloads (without the optional parameter in which case both the overloads becomes the same, neglecting constraint). Now when the constraint is applied, the call fails for Get<int> since int is not class.
Things change a bit when default parameter is provided. If I call
mango.Get(0);
The compiler is able enough to call the right overload, but which overload now accepts int or T where T: struct? There is not one. In the given example, the second parameter is expected to be T? and not T. The compiler doesnt automatically resolve overloading by applying all the available casts for every argument type. It isn't a bug, but thats one less a feature, thats all. If I do this:
int? i = 0;
mango.Get(i);
it works, the right overload is called. This is what is happening in the second example too. It works because I'm providing the right parameter.
When I call:
Guid? g = null;
g.IsIt();
obj is known to be g and hence T equals Guid. But if I call
Guid g = Guid.NewGuid();
g.IsIt();
This doesn't work, since g is now Guid and not Guid? and compiler doesnt do the casting automatically, instead one have to tell the compiler explicitly.
I'm ok with the fact that the compiler doesn't do the casting automatically since that will be too much to calculate for every possible type, but what appears to be a deficiency in C# is the fact that constraint checking is not involved in overload resolution. That is even if I provide the type like mango.Get<int>() or mango.Get<int>(0) the overload resolution won't prefer the struct version and use default(int?) for argument defaultValue. Looks odd to me.

Invalid implicit cast when casting array of interfaces to an array of structs

I have a struct that implements some interface. This works fine until I have an array of the struct implementation and try to implicitly cast that array to another array of the interface type. (See the below code example)
using System.Collections.Generic;
namespace MainNS
{
public interface IStructInterface
{
string Name { get; }
}
public struct StructImplementation : IStructInterface
{
public string Name
{
get { return "Test"; }
}
}
public class MainClass
{
public static void Main()
{
StructImplementation[] structCollection = new StructImplementation[1]
{
new StructImplementation()
};
// Perform an implicit cast
IEnumerable<IStructInterface> castCollection = structCollection; // Invalid implicit cast
}
}
}
When compiling the above code, I get the error:
error CS0029: Cannot implicitly convert type 'MainNS.StructImplementation[]' to 'MainNS.IStructInterface[]'
If I change StructImplementation to a class I have no problems, so I'm assuming what I'm trying to do is either not valid; or I'm being blind and missing something obvious.
Any advice or explanation for this would be appreciated.
EDIT
In case anyone else has this issue and using a different approach is less than ideal (as was the case in my situation), I worked around my issue using the LINQ method Cast<T>(). So in the example above, I would perform the cast using something like:
IEnumerable<IStructInterface> castCollection = structCollection.Cast<IStructInterface>();
There is a good article on MSDN about Variance in Generic Types, which I found very useful.
Array variance ony allows for the reference preserving case, and so only works for classes. It is essentially treating the original data as a reference to a different type. This is simply not possible with structs.
Convariance, which you are using here, is not supported for structs, because they are value types and not reference types. See here for a little bit more info.

How to convert from System.Enum to base integer?

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

Categories

Resources