I have a public enum declared like this:
public enum States
{
SomeState,
SomeOtherState
}
Having an arbitrary string myString which may represent any of the "States" above, I'd like to write a switch to check which one it currently is.
This is my attempt.
States state = Enum.Parse(States, myString, true);
switch (state)
{
case States.SomeState:
case States.SomeOtherState:
break;
default:
break;
}
Inside of the Enum.Parse() it tells me that the argument State is being used as a type instead that as a variable. Isn't that the correct usage? The first argument Enum.Parse is supposed to receive is Type enumType: why then it tells me it needs a variable?
Many kind replies indicates to use typeof. Unfortunately, I've already tried that but since I receive the following error I guessed it was a wrong idea.
Enum.Parse(typeof(States), myString, true);
yields:
cannot implicitly convert type 'object' to 'States'. An explicit conversion
exists.
Yes, you need to send in the Type of enum that your are parsing into (using typeof):
States state = (States)Enum.Parse(typeof(States), myString, true);
The Parse method is expecting an argument of type System.Type. Not the type States.
Here is the signature from the docs.
[ComVisibleAttribute(true)]
public static Object Parse(
Type enumType,
string value,
bool ignoreCase
)
Parse returns an object so it requires you to cast to your type after the parse.
Since it is expecting a type, change Enum.Parse(States, myString, true); to Enum.Parse(typeof(States), myString, true);
This is the correct one.
States state = Enum.Parse(typeof(States), myString, true);
switch (state)
{
case States.SomeState:
case States.SomeOtherState:
break;
default:
break;
}
States tmp;
Enum.TryParse<States>(myString,true ,out tmp);
Can make it more elegant by using extension class like so:
namespace YourClass.Models;
public static E ToEnum<E>(this object value, bool ignoreCase = true) where E : Enum
{
if(value == null)
{
throw new ArgumentNullException("Value cannot be null");
}
return (E)Enum.Parse(typeof(E), value.ToString(), ignoreCase);
}
And using it like so:
States state = myString.ToEnum<States>();
Related
I'm trying to do this:
const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
case intType:
{
return "int";
break;
}
...
}
But compiler says:
error CS0133: The expression being assigned to 'intType' must be constant
As I know, typeof operator works at compile-time. So, what's wrong?
As I know, typeof operator works at compile-time.
You don't know that because knowledge has to be true. Where did you get the idea that typeof is executed at compile time? It produces a non-constant object. And then there is no guarantee that ToString doesn't produce a different string every time it runs, so it cannot be treated as a constant either.
So, what's wrong?
You're reasoning from a false belief.
The C# specification clearly describes the conditions that must be met for an expression to be a compile-time constant. Those conditions include the expression not containing any typeof operator or method call.
But there are far bigger problems here. I assume that MyT is a generic type parameter, which means you are attempting to switch on the value of a generic type parameter. That is almost always the wrong thing to do.
What are you really trying to do? What problem are you really trying to solve? Because this code you've shown so far indicates that you're going down an unproductive path to solve whatever the real problem is.
I think, it is quite obvious, what he wants to achieve:
He wants to check for type equality in a switch-case instead of via if-elseif. And to be honest, why not? But how can he achieve this?
First option: Wait for C# 7.0. Yeah, shit like this is possible in the future!
Second option: Use strings. But the case strings need to be constant. So what about the wonderful nameof?
I just tried this "beauty" and it works, so maybe this solves your problem:
switch (typeof(Int32).Name)
{
case nameof(Int32):
Console.WriteLine("It's an Int32!");
break;
case nameof(Double):
Console.WriteLine("It's a Double");
break;
}
The only way to compare type MyT with known types is by checking their Type objects for equality. This can be done as follows:
if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...
You cannot use this approach in a switch because (at the moment) a switch requires that the item being checked is of a simple type:
switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
// char, string, integral, enum, or corresponding nullable type"
{
case typeof(int): return "int";
case typeof(decimal): return "decimal";
// ...
}
Also, as others already said, checking types in this way almost always means that your approach can be improved by applying different object oriented principles.
E.g. instead of MyMethod<MyT>(MyT item) with type checks for MyT, consider making MyMethod(int item), MyMethod(decimal item) etc.
If you are just trying to get a string describing the type of object, you just need to call .GetType() instead.
For example, the following is a small function that will return the string name of the object type.
static string GetTypeString(object obj)
{
return obj.GetType().FullName;
}
This will return to the full path to the object. In int's case, it will return System.Int32. If you only want the Int32 part, use GetType().Name instead.
Also, you don't need to have a break; in a switch if you have a return;
If you have specific code that needs to be run for some types, or a specific string you want to return, you can use a string on the values returned by the above. For example:
static string GetSimpleType(object obj)
{
var stringRepresentation = GetTypeString(obj);
switch (stringRepresentation)
{
case "System.Int64":
case "System.Int32":
return "int";
default:
return stringRepresentation;
}
}
default is a catch all in switch statements for everything that does not have a case. Think of it like an else.
In the above example, we return the same value for int, Int32, and Int64. Case labels can fall through to other case labels if they are empty.
You can find all the values you need to write a switch for by running a simple script, and hard code the string values since they will always be the same for the same types. If the string is different, then the type is different.
Finally, if you are comparing types, if and if else works better:
static string GetSimpleType(object obj)
{
if (obj.GetType() == typeof(int))
{
return "int";
}
return obj.GetType().ToString();
}
I want to create a method that takes a dynamic input parameter and returns a dynamic that I can use to fill a typed variable. Is there a way to get the type of the variable being assigned to from within the method?
double dbl = AssignValue("Hello");
public dynamic AssignValue(dynamic ValueToAssign)
{
Type type = //do something to get the type of variable "dbl"
switch (type.Name)
{
case "Double":
return double.Parse(AssignValue);
break;
case "Decimal":
return decimal.Parse(AssignValue);
break;
//...
}
}
I tried to locate something in the StackFrame but, with no luck.
Any terminology to research further would be very much appreciated as well.
Is there a way to get the type of the variable being assigned to from within the method?
No. There is no way for a method to retrieve any information about the variable that its result will be assigned to.
However, you could use generics to tell the method the type of object you want it to return:
double dbl = AssignValue<double>("Hello");
public T AssignValue<T>(object valueToAssign)
{
Type type = typeof(T);
switch(type.Name)
{
//...
}
}
Is there any way to make an out parameter of a method optional? I have a method that needs several parameters to return null most of the time, but sometimes they will have a value. I am trying to find out if there is a better way to accomplish this than by setting the values to null first, or setting them to null after the if/else. This may be the only way to do it, but it would be nice if there were optional out parameters or something equivalent. Here is the code:
private static void GetInitInfo(string initLine, string ncPointType, out double? relinquishDefault, out bool? ignoreRelinquishDefault, out bool? closedForStart, out bool? adjustDisabled)
{
relinquishDefault = null;
ignoreRelinquishDefault = null;
closedForStart = null;
adjustDisabled = null;
switch (ncPointType)
{
case "MSD":
adjustDisabled = LastToken<bool?>(initLine);
break;
case "BO":
relinquishDefault = SecondToken<double>(initLine);
closedForStart = ThirdToken<bool?>(initLine);
ignoreRelinquishDefault = !ForthToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value
break;
case "MSO":
closedForStart = SecondToken<bool?>(initLine);
relinquishDefault = ThirdToken<double>(initLine);
ignoreRelinquishDefault = !ForthToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value
break;
case "AD":
relinquishDefault = ThirdToken<double>(initLine);
ignoreRelinquishDefault = false;
break;
case "BD":
relinquishDefault = SecondToken<double>(initLine);
adjustDisabled = LastToken<bool?>(initLine);
ignoreRelinquishDefault = false;
break;
case "AOS":
relinquishDefault = FirstToken<double>(initLine);
ignoreRelinquishDefault = !ThirdToken<bool?>(initLine);//ignoreRelDef would be reverse of use initial value
break;
}
}
This isn't not allowed according to the C# 4.0 Spec: section 21.1.
A workaround is to overload with another method that does not have out or ref parameters.
I believe this question is asking about having to assign values inside the method with out parameters, and whether there is any way to circumvent that, i.e. by leaving the values unassigned rather than explicitly having to assign them null.
e.g. Do you have to write:
public bool OutMethod(out int? output)
{
output = null;
return true;
}
Or is there a way to do something like:
public bool OutMethod(out int? output)
{
return true;
}
With the same result?
Short answer is no, this can't be avoided. See the documentation for an example which includes assigning null explicitly, and states:
Note that the third argument is assigned to null. This allows methods to return values optionally.
Examples of this can also be found in the .NET framework. e.g. Dictionary<TKey,TValue>'s TryGetValue method:
public bool TryGetValue(TKey key, out TValue value)
{
int num = this.FindEntry(key);
if (num >= 0)
{
value = this.entries[num].value;
return true;
}
value = default(TValue);
return false;
}
Note the explicit assignment to default(TValue)
Use the overload with signature that does not have out parameters:
private static void GetInitInfo(string initLine, string ncPointType)
{
double? relinquishDefault;
bool? ignoreRelinquishDefault;
bool? closedForStart;
bool? adjustDisabled;
GetInitInfo( initLine, ncPointType, out relinquishDefault, out ignoreRelinquishDefault,
out closedForStart, out adjustDisabled);
}
The explanation is quite simple: You can do it. Just assign an out parameter inside the method to the desired value.
Now you can ask yourself, why can't we do that in the method signature? Well, let us have a look at the normal optional value parameters. They are assigned a predefined value if they are not assigned by the caller. So caller knows the value, which will be passed if the parameter is not set explicitly. It has a control of it and it is responsible for that decision.
Since the caller of the method is NOT responsible for the assignment of the out parameter, it makes no sense to offer a default value. The only thing you could achieve, by having a default out parameter value is to let the caller know what one of the possible values of that out parameter would be. But would that make sense? When will this value be used? Under what condition? All this is still hidden from the caller. So there is no real benefit from having an optional out parameter value, apart from having a possiblity to set it inside the signature instead of the method body.
So, having that said, the following would not make much sense:
public bool TrySomething(out string outObject = "default value") { ... }
However, what would be cool is to allow the following method
public bool TrySomething(out string outObject) { ... }
to be invoked as follows:
bool result = TrySomething();
And have that behind the scenes equivalent to:
string dummyWhichWillNeverBeUsed;
bool succeeded = TrySomething(out dummyWhichWillNeverBeUsed);
Unfortunately, that is not allowed.
And of course, as explained in other answers, you can always have overloads without out parameter.
I have the following enum declaration:
enum MyType
{
Boolean,
Int,
Double,
String
}
Then if I have a string abc = "anyvalue", how can I check whether the abc value is either bool, int, double or string corresponding to a myType enumerated value?
You can use Enum.TryParse method. This will return true if the value was successfully parsed into one of the enumeration values while also outputting the parsed enumeration value.
If you want to ignore case when performing the parsing use the overload that accepts a boolean parameter.
MyType type;
if (Enum.TryParse(abc, out type))
{
// can be parsed
switch (type)
{
case MyType.Boolean: break;
case MyType.Int: break;
case MyType.Double: break;
case MyType.String: break;
}
}
It's also possible to use Enum.IsDefined but this method always does a case-sensitive search so it is less flexible than Enum.TryParse and can only be used to know if the name is defined or not.
Use this:
MyType dummy;
if(bool isEnum = Enum.TryParse(mystring,out dummy))
{
// mystring is a valid enum
}
I have defined a C# enum as
public enum ORDER
{
...
unknown,
partial01,
partial12,
partial23,
}
and can use its value as a string as in:
string ss = ORDER.partial01.ToString();
However when I try to use it in a case statement it fails to compile:
string value = ...
switch (value)
{
case null:
break;
case "s":
// OK
break;
case ORDER.partial01.ToString():
// compiler throws "a constant value is expected"
break;
...
I thought enums were constants. How do I get around this?
(I cannot parse the value into an enum as some of the values are outside the range)
Since C# 6, you can use: case nameof(SomeEnum.SomeValue):
Nameof is evaluated at compile time, simply to a string that matches the (unqualified) name of the given variable, type, or member. Naturally, it changes right along should you ever rename the enum option name.
Convert the string in your switch to an enum value.
(ORDER)Enum.Parse(typeof(ORDER), value, true);
The enum is a constant, but the result of .ToString() is not. As far as the compiler is concerned, it is a dynamic value. You probably need to convert your switch case into a series of if/else statements
As an alternative to using if .. else, you could convert your string to an enum first. It would probably not make much sense if the number of options is small though:
if (Enum.IsDefined(typeof(ORDER), value))
{
switch ((ORDER)Enum.Parse(typeof(ORDER), value)
{
case ORDER.partial01:
// ...
break;
case ORDER.partial12:
// etc
}
}
else
{
// Handle values not in enum here if needed
}
*sigh* if only there was a built-in T Enum.Parse<T>(string value), and a TryParse version :)
You designed this as an enum for a reason, but you're not really making use of it as an enum. Why are you taking the enum value and converting it to a string to then use in the switch instead of simply using the enum?
You said that you can't parse this in to an enum because some of the values are outside the enum range. The question to ask then is, "Why?" What is the point of having the enum if you are allowing values that aren't defined? What is it that you want to happen when you get a value that isn't defined? If it's the same thing for any undefined value, then you can use the default case. If it's not, then you can include additional cases that match the numeric representation.
If you really do get strings back, then you probably don't want to use an enum. Instead you want to create a public static class containing public string constants, which you can then use in your switch. The trick here is that the evaluation will be done in a case sensitive manner.
public static class Order
{
public const string Unknown = "Unknown";
public const string Partial01 = "Partial01";
public const string Partial12 = "Partial12";
public const string Partial23 = "Partial23";
}
string value = Order.Partial01
switch (value)
{
case Order.Partial01:
break;
default:
// Code you might want to run in case you are
// given a value that doesn't match.
break;
}
(You might also want to clean up your casing.)
As Thorarin indicated, if your switch statement can contain only enum cases, convert your string to an enum first. At least as of .Net framework 4, you can use the Enum.TryParse()<TEnum> method as defined here and do something like:
ORDER orderEnum = ORDER.unknown;
Enum.TryParse<ORDER>(value, out orderEnum);
switch (orderEnum)
{
case ORDER.unknown:
// perhaps do something to deal with cases not matching
// to known enum values, based on the string value
break;
case ORDER.partial01:
case ORDER.partial12:
case ORDER.partial23:
// map value to known cases, etc.
break;
}
Enum values are constants, but you're trying to use the results of a method (ORDER.partial01.ToString()), not a constant.
The best option, in my opinion, would be to just switch this around to using if/else if/else statements, instead of a switch. This would allow you to use the logic you are desiring.
Alternatively, if you switch your string into the enum value, you can switch on the enum values directly. You cannot switch on the enum + null + other strings, though, in one switch.
Couldn't you just instead say
case "partial01":
?
enums are constant but ToString() is a function returning a value. based on the instance of the enum object it's being called on.
That is the two statements:
ORDER.partial01.ToString()
ORDER.partial02.ToString()
calls the same function but returns two different values, so the call to the function .ToString() is in it self not a constant value.
This is not a static value as far as the compiler is concerned, since it is a function call:
ORDER.partial01.ToString()
Therefore, you can't use it as a comparison in a case statement. However, you can simply do this:
case "partial01"
That would work, since the enum value and the string are identical.
Use Extension
public static string ToGender(this Gender enumValue)
{
switch (enumValue)
{
case Gender.Female:
return "Female";
case Gender.Male:
return "Male";
default:
return null;
}
}
Example
Gender.Male.ToGender();
simply you can define a global variable
static ORDER orderstr;
now you can set the value of orderstr anywhere in the page
public enum ORDER
{
unknown,
partial01,
partial12,
partial23,
}
switch (orderstr)
{
case Order.Partial01:
break;
default:
break;
}