So I am trying really hard to change the underlying number value of an Enum. Take this example:
[Flags]
public enum Foo
{
Foo = 1,
Bar = 2,
FooBat = 4
}
With a simple extension methods for enums. In his method I want to remove all flags from the enum itself:
public static TEnum GetBaseVersionOfEnum<TEnum>(this TEnum enumVal) where TEnum : Enum
{
var tempEnum = enumVal & 0 // I would like to do something like that. e.g. setting its underlying value to zero.
return tempEnum;
}
Note that it is possible to set an enum to zero, even if there is no matching enum member.
To clarify what I want to achieve, here a few samples:
Foo.Bar.GetBaseVersionOfEnum() should return Foo with the value of 0.
(Foo.Bar | Foo.Foo).GetBaseVersionOfEnum() should return Foo with the value of 0.
I actually achieved that, but it is hella ugly, at least IMO, by using some reflection. I really hope there is a cleaner and faster way to do this.
var dynamicVal = (dynamic)enumVal;
dynamicVal.value__ = 0;
var tempEnum = (Enum)dynamicVal;
I actually stumbled over the value__ field by some testing with reflection, which revealed that there is actually a public field which exposes the current value.
This also makes me wonder why you can't access it by using the dot (enumVal.value__)... I guess it is some kind of runtime field.
I might be deeply confused by your question, but to me it seems you're trying to make a convoluted way of saying default:
public static TEnum GetBaseVersionOfEnum<TEnum>(this TEnum enumVal) where TEnum : Enum
{
return default;
}
The default value for an enum is all-zero bits (the default for the underlying value type). But why do you need a helper for that at all? You can literally say
Foo allzero;
And you get an all-zero enum of your type. Or say
myExistingEnum = default;
to zero an existing variable out.
Related
In my current project, i have a Value<T> class.
Currently T can be anything, but we must support Null values, so currently we use it in two forms:
Value<string> or Value<int?>
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
The goal is to avoid the case where a developer specifies Value<int> and we later have problems, because we dont handle Null values properly.
Ie, id like Compiler suport for avoiding errors.
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
No, because you cannot have "or" logic in generic type constraints.
To achieve "or" logic in generic type constraints, you would have to create two separate generic classes, each with their own generic type constraint. Note that these two classes could inherit from a shared generic base class which has no type constraint at all.
If that base type is abstract, then you can be sure that consumers must have passed one of the derived classes' type constraint check (assuming no one added some other derived classes)
It would be more appropriate to change your expectation instead of trying to make it the way you currently want to.
but we must support null values
If instead of null, you use default(T), then the problem is resolved.
For class types, default(MyClass) effectively resolves to null
For structs, default(MyStruct) returns a struct whose properties all contain their default values
default(MyStruct) is the common way to use the concept of "nullability" without having to use a literal null value.
A usage example:
public class Container<T>
{
private readonly Random _random = new Random();
public T DoSomething(T input)
{
//always returns "nothing"
return default(T);
}
}
public class MyClass
{
public int Value { get; set; }
}
public struct MyStruct
{
public int Value { get; set; }
}
public class Test
{
public bool ContainerReturnsNothing<T>(T input)
{
var container = new Container<T>();
var output = container.DoSomething(input);
return output.Equals(default(T));
}
public void TestAClassAndAStruct()
{
ContainerReturnsNothing(new MyClass() {Value = 1}); // true
ContainerReturnsNothing(new MyStruct() {Value = 1}); // true
}
}
In the TestAClassAndAStruct method you can see that this generic call stack works exactly the same regardless of whether you use a class or a struct.
If you change the container to return input; then ContainerReturnsNothing will return false in both cases.
One thing you may need to be aware of is that a "nothing" struct cannot be differentiated from a struct that was created but whose properties all happen to have default values. If a struct whose properties all happen to have default values, is a meaningful (i.e. not-nothing) struct value in your case, then this is an issue.
A simple example here is int, whose default(int) resolves to 0. If 0 is a meaningful value, then it is therefore not nothing, which means that you cannot use 0 to represent nothingness.
But you can work around that issue by adding a property which is forced to contain a non-default value when a constructor is executed:
public struct MyStruct
{
public bool IsConstructed { get; } // default false
public int Value { get; }
public MyStruct(int myValue)
{
this.IsConstructed = true;
this.Value = myValue;
}
}
default(MyStruct) will always have IsConstructed set to false.
Every instantiated struct will always have IsConstructed set to true.
This avoid the issue since they will never be equal to one another. In other words:
var myStruct = new MyStruct(0);
var isNull = myStruct.Equals(default(MyStruct));
isNull is false because myStruct and default(MyStruct) contain a different value for IsConstructed (true and false, respectively).
If you run this same check using the MyStruct class from the original example, isNull would be true because all the properties match, i.e. myStruct and default(MyStruct) both have a Value property set to 0.
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
I have many Enum types which return from a service and which I want to map to my Enum types.
What I want is to create a mapper class which has all the conversion logic.
I did something like this:
public static class ErrEnumMapper
{
private static Dictionary<FullErrorTypeError, eError> dictionary;
static ErrEnumMapper()
{
var dictionary = new Dictionary<FullErrorTypeError, eError>()
{
{FullErrorTypeError.APP, eError.APPLICATION},
{FullErrorTypeError.INF, eError.INF},
{FullErrorTypeError.NO, eError.NONE},
{FullErrorTypeError.PAX, eError.PASSENGER},
{FullErrorTypeError.SYS, eError.SYSTEM}
};
}
public static eError GetEnum(FullErrorTypeError key)
{
var val = dictionary[key];
if (val != null)
return val;
throw new InvalidOperationException();
}
}
But since I have many other Enums, in this way, I will have to create many static fields (like the "dictionary" fields) and their equivalent method (Like "GetEnum")...is there a better way to do this?
Generic maybe?
Unless the integral values or names are the same for both sets of enums are the same, you can't transpose from one enum value to another without some sort of manual mapping.
Some suggestions:
Reuse the original enums if possible
Keep the integer values of the mapped enum the same as the original enum, so you can just cast from one to another.
Use a convention for the enum names so you can map from one to the other.
Use a custom attribute on each mapped enum value that indicates the correlating original enum value, and have ErrEnumMapper read that attribute. Still manual mapping, just perhaps reorganized.
Of course, in the spirit of KISS, I'd stick with #1, #2, or just deal with the manual mapping.
Maybe I'm not really getting what you mean.. but you can just explicitly cast them if they have the same underlying value:
enum FirstEnum {
ONE,
TWO,
THREE
}
enum SecondEnum {
FOUR,
FIVE,
SIX
}
static void Main(string[] args) {
FirstEnum first = FirstEnum.ONE;
SecondEnum second = (SecondEnum)first;
Console.WriteLine(second); // prints FOUR
}
This allows you to keep your naming convention..
Enums are generally used to define the state of a particular property of a class, say in an object model of some sort. For some of these properties, the state 'this property is not set' is valid.
In these situations, should I use a zero None enum value, or make the property type nullable?
public MyEnum Property { get; set; }
public enum MyEnum {
None = 0,
Value1,
Value2
}
or
public MyEnum? Property { get; set; }
public enum MyEnum {
Value1,
Value2
}
Use MyEnum.None - it is much more expressive, or even MyEnum.Invalid to convey meaning.
You can also set it to other values than 0 - since it is based on int, you can set it to be -1 and the first valid value to 1:
public enum MyEnum {
InvalidValue = -1,
Value1 = 1,
Value2
}
In your code you can easily check for this value being passed in and throw a descriptive exception.
A nullable enum type is not expected and less expressive. It requires users of you code to be aware of this and check for nulls.
It's hard to answer this conclusively, a lot of factors in your app will influence this. I tend to just define the enum value to 0, but not specify a zero value in the enum.
enum Foo
{
A = 1,
B = 2
}
...
Foo myFoo = (Foo)0;
This gives the benefit of a sentinel value, without polluting the enum.
I would use the "None" value instead of a nullable enum. If nothing else, to me if(Property == MyEnum.None) is a lot more readable than if(Property == null).
Another option is to set the first value to 1, since it will be initally 0.
public enum MyEnum {
Value1 = 1,
Value2
}
I think both of your situations are acceptable! It will depend upon your situation. When working with a user interface your first example with the 'None' value will probbaly be easier to use. However, the Nullable gives more information about how the variable should be used.
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);