Related
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.
For converting a string to an enum, which of the following ways is better?
This code:
colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green");
or this:
string colorString = ...
colorEnum color;
switch (colorString)
{
case "Green":
color = colorEnum.Green;
break;
case "Red":
color = colorEnum.Red;
break;
case "Orange":
color = colorEnum.Orange;
break;
....
}
You should use the Enum.TryParse, if it fails you can handle the error correctly.
sample:
ColorsEnum colorValue;
if (Enum.TryParse(colorString, out colorValue))
if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))
Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
else
Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
else
Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString);
(Warning: includes plug for my own open source library...)
Personally I'd use Unconstrained Melody, which ends up with cleaner and more typesafe code:
ColorEnum color = Enums.ParseName<ColorEnum>(text);
You can use TryParseName if you suspect it may be invalid. Obviously this requires an extra library, but hopefully you'll find other things in there helpful too :)
Enum.TryParse from .NET 4 is better than the other built-in options, but:
You won't catch non-enum types at compile time, e.g. Enum.TryParse<int>(...) will still compile; Unconstrained Melody really only allows enum types
Enum.TryParse will also parse "1" (or whatever the numeric value is when converted to a string) - if you really only expect names, I think it's better to only accept names
I definitely wouldn't switch on the string values - it means if you rename the enum values, you've got to remember to rename the case value as well.
And what about Enum.TryParse<TEnum> ?
string myColorStr = "red";
colorEnum myColor;
if(!Enum.TryParse<colorEnum>(myColorStr, true, out myColor))
{
throw new InvalidOperationException("Unknown color " + myColorStr);
}
Number 1 simply on readability and maintainability. If you extend the enum you need to do no extra work, wheras with 2 you have to add more cases to the switch statement
Because you added the tag 'performance', I'm going to go with the switch.
Yes, you will have to change the cases when you rename/add/remove anything in the enum. Well that's just too bad then. Any variant of Enum.Parse/TryParse uses a lot of weird code and some reflection, just take a look inside the function with ILSpy or such. Then there is also the issue of accepting "-12354" and even a comma-separated list of valid names (resulting in all of them ORed together) even when the enum doesn't have a [Flags] attribute.
As an alternative, you could make a dictionary that translates enum names to values. It should actually be faster than the switch, because a switch on strings also goes through a dictionary but you save the actual switch part.
Obviously both ways cost some more maintenance than enum.parse and variants; whether it's worth it is up to you, since out of all of us only you have enough knowledge of the project to make the performance/coding-time trade off.
1) Is much better. It's cleaner code. You are doing in one line what would take multiple in 2). Also, it's less bug prone. When you add another item to colorEnum, you would need to remember to extend 2) wheras 1) would just work.
You may also want some error handling on the Enum.Parse.
Other than the fact that the two different code snippets doesn't do the same thing, I'd use this:
colorEnum color;
if (!colorEnum.TryParse(colorString, true, out color)
color = colorEnum.Green; // Or whatever default value you wish to have.
If you don't have .NET 4.0 then I'd do something like this:
public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
return defaultValue;
return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}
This is an Extension Method to string.
Personally, while I am totally fine with the Enum.Parse solution for non-performance scenarios (read: one off run of this function occasionally ... and there are many such scenarios to be sure), I can't countenance the thought of possibly involving some reflection type method when this function needs to be performed in a loop over hundreds/thousands plus enum values at once. Gack!
So the following is a solution that gets some of the best of both worlds.
Just retrieve all values of the enum at startup time or what not, whenever it works best for you (below is one way of doing that), and then construct a Dictionary with them.
private static Dictionary<string, Color> colorDictionary;
public static Dictionary<string, Color> ColorDictionary
{
get
{
if (colorDictionary== null) {
colorDictionary = new Dictionary<string, Color>();
var all = Enum.GetValues(typeof(Color)).OfType<Color>();
foreach (var val in all)
dict.Add(val.ToString(), val);
}
return colorDictionary;
}
}
I find the switch variant horrible since you will have to modify the switch everytime you change the enum also.
I like to use the TryParse that belongs to your enum. So you can use it like this
string colorString = .....
colorEnum color;
colorEnum.TryParse(colorString, out color);
Or if you don't care about the case of the string
colorEnum.TryParse(colorString, true, out color);
The returnvalue of TryParse is true if the string was a valid enum, false if not.
On a performance point of view, as enums are implemented as static fields, the parse method will probably ends up doing refection on then enum type and try a GetField method which might be faster than the case. On the other end, if 90% of the case, the color is green, the case will be very fast... Note that the CLR sometimes rearrange code internally, changing the order of the case based on statistic (actually, I'm not sure it does that but the doc claims it could).
I use the following, it gets you all the type safety while still not falling over when you add new values into the Enum, it's also very fast.
public static colorEnum? GetColorFromString(string colorString)
{
colorEnum? retVal = null;
if(Enum.IsDefined(typeof(colorEnum), colorString))
retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString);
return retVal;
}
My test with 8 items in the enum shows this way to be faster than the switch method.
Or else you can use (the very slow way):
public static colorEnum? GetColorFromString(string colorString)
{
foreach (colorEnum col in Enum.GetValues(typeof(colorEnum)))
{
if (col.ToString().Equals(colorString))
{
return col;
}
}
return null;
}
Why does
Convert.ToBoolean("1")
throw a System.FormatException?
How should I proceed with this conversion?
Yes, this is as documented:
[throws] FormatException [if] value is not equal to TrueString or FalseString.
TrueString is "True" and FalseString is "False".
If you want to detect whether a string is "1" or not, use this code:
bool foo = text == "1";
Depends on what you want. Perhaps
var result = Convert.ToInt32(yourstirng) != 0
assuming any number but 0 is true. Otherwise a simple comparison would work.
var result = yourstirng == "1"
The parameter must be equal to either Boolean.TrueString or Boolean.FalseString. The values of these strings are "True" and "False", respectively. See MSDN.
The string value "1" is obviously not equal to "True" or "False".
The problem is, that youre giving a String here, not a number. It cant convert the String "1" to true, but the int 1.
Convert.ToBoolean(1);
should work.
When converting to Boolean it is best to use your own routine, where you handle all cases. .net Convert.ToBoolean isn't a practical routine, it is one of those function where you have to explain why it doesn't work.
I know this is old, but in case someone searches... simply do this:
Convert.ToBoolean(Convert.ToInt16("1")) works just fine. Not pretty, but needs be.
Another solution is to use an Extension Method on the string object. I used this technique in a case where I had to parse CSV files that had different strings that had to be converted to boolean values depending on their source and format.
public static class StringExtensions
{
public static bool ToBool(this string value,string trueValue)
{
if (value == trueValue)
{
return true;
}
else
{
return false;
}
}
}
This would be called like so...
MyProperty = CsvColumn[6].ToBool("1");
If you want, the truevalue parameter could be a string array if you needed to compare multiple values (like n/a, na, none) and you could add in false values if you want to further restrict it or use nullable types.
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;
}
I have an enum
public enum FileExtentions {
mp3,
mpeg
}
And I have a FileInfo of which I want to check if the extension is in the previous enum.
I was hoping I could do a
FileExtensions.Any(e=>e.ToString().Equals(file.Extension));
But that would have been too awesome.
Any ideas?
What's the reason behind Any … Equals? Did you overlook Contains?
bool result = Enum.GetNames(typeof(FileExtensions)).Contains("mp3");
While pressing submit I thought of the answer myself:
Enum.GetNames(typeof(FileExtensions)).Any(f=>f.Equals("."+file.Extension))
Enum.IsDefined will take a string containing the name of an enum value. The only ugliness is that you have to strip the leading period off of File.Extension and it's case sensitive:
Enum.IsDefined(typeof(FileExtension), file.Extension.Substring(1).ToLower())
Edit: Extension method goodness to get close to your desired syntax:
IEnumerable<string> GetNames(this Type t) {
if (!t.IsEnum) throw new ArgumentException();
return Enum.GetNames(t);
}
typeof(FileExtensions).GetNames().Any(e=>e.ToString().Equals(file.Extension));
Personally, though, I'd still rather the IsDefined route:
bool IsDefined(this Type t, string name) {
if (!t.IsEnum) throw new ArgumentException();
return Enum.IsDefined(t, name);
}
typeof(FileExtension).IsDefined(file.Extension);
You can extend the FileInfo type with the following extension method:
public static bool HasExtension(this FileInfo file)
{
var ext = file.Extension.StartsWith(".") ? file.Extension.Substring(1)
: file.Extension;
return Enum.GetNames(typeof(FileExtensions))
.Any(f => f.Equals(ext));
}
and use it like:
bool hasExtension = file.HasExtension();
You can do that with the System.Enum type:
string extension = Enum.GetName(typeof(FileExtensions), FileExtensions.mp3);
if (extension == file.Extension)
// do something here
Update:
Ah, I misunderstood that you want to check the entire enum for the extension and not that a specific enum value matches the extension. In that case, your approach with GetNames() is the route - sorry you can't mark your own answer as accepted for your own question. ;-)
The best way is to use Enum.IsDefined function. It pretty easy, in your case:
if (Enum.IsDefined(typeof(FileExtentions), file.Extension))
General solution:
Enum.IsDefined(Type, Object)
Your solution is:
Enum.IsDefined(typeof(FileExtentions), FileInfo)