Returning an array in case switching C# - c#

I am trying to return an array with a date [sStartMonth, sStartDay, sStartYear] for a specific case, for example: case: "Today" will return {"June", "3", "2015"}.
I am trying something like this but fail:
public static string[] SetStartDate(string sStartDateFilter)
{
switch (sStartDateFilter)
{
case "Today":
DateTime currentDate = DateTime.Now;
string sStartMonth = currentDate.ToString("MMMM");
string sStartDay = currentDate.Day.ToString();
string sStartYear = currentDate.Year.ToString();
return {sStartMonth, sStartDay, sStartYear};
}
}

To construct an array in-line you need the full syntax, the short-hand syntax you're using is only allowed when explicitly declaring an array and giving it a value in the same statement.
So this is what you want:
return new[] { sStartMonth, sStartDay, sStartYear };

Something like:
switch (sStartDateFilter)
{
case "Today":
return new[] { sStartMonth, sStartDay, sStartYear };
default:
// return something here or throw
You will need to return something for the default case too, or throw a new ArgumentOutOfRangeException("sStartDateFilter") or you will get a compiler error as not all paths will return a value.

To combine the answer of #Lasse V. Karlsen with my potential answer:
public static string[] GetStartDate(string sStartDateFilter)
{
DateTime currentDate = DateTime.Now;
switch (sStartDateFilter)
{
case "Today":
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
case "Tomorrow":
currentDate.AddDays(1);
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
case "Yesterday":
currentDate.AddDays(-1);
return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()};
default:
// all other cases
}
}
EDIT:
I know, that I should move the line return new string[]{ currentDate.ToString("MMMM"), currentDate.Day.ToString(), currentDate.Year.ToString()}; into a separate function, but this is only a simple example

Related

Convert System.DayOfWeek into Microsoft.Office.Interop.Outlook.OlDaysOfWeek

Is there a possibility to directly convert a value of System.DayOfWeek into a value of Microsoft.Office.Interop.Outlook.OlDaysOfWeek. Something like:
var day = DayOfWeek.Friday;
OlDaysOfWeek days = ConvertToDaysOfWeek(day);
To do this without using string manipulation, here's an option:
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
return (OlDaysOfWeek)Math.Pow(2, (int)day);
}
You can try this:
var olDay = (OlDaysOfWeek) Enum.Parse(typeof(OlDaysOfWeek), $"ol{systemDay}");
A simple switch statement would probably be most performant:
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
switch (day)
{
case DayOfWeek.Monday: return OlDaysOfWeek.olMonday;
case DayOfWeek.Tuesday: return OlDaysOfWeek.olTuesday;
case DayOfWeek.Wednesday: return OlDaysOfWeek.olWednesday;
case DayOfWeek.Thursday: return OlDaysOfWeek.olThursday;
case DayOfWeek.Friday: return OlDaysOfWeek.olFriday;
case DayOfWeek.Saturday: return OlDaysOfWeek.olSaturday;
case DayOfWeek.Sunday: return OlDaysOfWeek.olSunday;
default: throw new ArgumentOutOfRangeException("What day is this?", "day");
}
}
Alternatively, you could probably parse the value and return the mapped value based on the enum value name.
public OlDaysOfWeek ConvertToDaysOfWeek(DayOfWeek day)
{
return (OlDaysOfWeek) Enum.Parse(typeof(OlDaysOfWeek), "ol" + day.ToString());
}
The OlDaysOfWeek enum utilises a power-of-2 sequence, which is typically used when combining values as bitwise flags. DaysOfWeek has a simple linear sequence reflected as 0-6 - this is why you can't compare using the backing int value
Finally I found the following solution. Thanks for the hints.
public static OlDaysOfWeek AsDaysOfWeek(this DayOfWeek dayOfWeek)
{
return (OlDaysOfWeek)(1 << (int)dayOfWeek);
}
To be used like this:
var day = DayOfWeek.Friday;
OlDaysOfWeek days = day.AsDaysOfWeek();
Additionally these are the unit tests in NUnit for the method:
[TestCase(DayOfWeek.Monday, OlDaysOfWeek.olMonday)]
[TestCase(DayOfWeek.Tuesday, OlDaysOfWeek.olTuesday)]
[TestCase(DayOfWeek.Wednesday, OlDaysOfWeek.olWednesday)]
[TestCase(DayOfWeek.Thursday, OlDaysOfWeek.olThursday)]
[TestCase(DayOfWeek.Friday, OlDaysOfWeek.olFriday)]
[TestCase(DayOfWeek.Saturday, OlDaysOfWeek.olSaturday)]
[TestCase(DayOfWeek.Sunday, OlDaysOfWeek.olSunday)]
public void AsDaysOfWeek(DayOfWeek dayOfWeek, OlDaysOfWeek expectedResult)
{
var result = dayOfWeek.AsDaysOfWeek();
Assert.That(result, Is.EqualTo(expectedResult));
}

C# - Looking for a simple way to parse a string value between two different representations (numerical and english)

I'm currently developing a small helper application for something, and was wondering if there were a better way to accomplish this one thing -
I have a CSV file that I am reading into my program, and I am parsing one of the values in each row from a numerical value (always an integer, between 1 and 5) to a string value for easier representation within the program. When I save the file, I need to convert back from the string representation to the numerical representation. Currently, I am doing this via a switch statement but I know there must be a terser way to accomplish this.
The function I am currently using takes two arguments. One of the arguments is a string that can be either the numerical representation or the string representation of that value I am trying to parse, and the other value is a boolean that tells the function which way it should convert the first argument. If the boolean argument is true it converts to a numerical representation, and if false it converts to the string representation. Here is my function to parse the value:
string ParseRarity(string rarity, bool toNumericalStr)
{
if (toNumericalStr)
{
switch (rarity)
{
case "Very Common":
return "1";
case "Common":
return "2";
case "Standard":
return "3";
case "Rare":
return "4";
case "Very Rare":
return "5";
}
}
else
{
switch (rarity)
{
case "1":
return "Very Common";
case "2":
return "Common";
case "3":
return "Standard";
case "4":
return "Rare";
case "5":
return "Very Rare";
}
}
return "";
}
Any help with shortening this code would be greatly appreciated, so "thank you" in advance!
I'll toss an answer in too, you could create a static "repository" class that contains your rarity values. The underlining storage mechanism is a Dictionary<int, string>. This will force all your rarities to have a unique key (the int), and it will be fast to access by that key.
public static class RarityRepository
{
private static Dictionary<int, string> _values = new Dictionary<int, string>()
{
{ 1, "Very Common" },
{ 2, "Common" },
{ 3, "Standard" },
{ 4, "Rare" },
{ 5, "Very Rare" },
};
public static string GetStringValue(int input)
{
string output = string.Empty; // returns empty string if no matches are found
_values.TryGetValue(input, out output);
return output;
}
public static int GetIntValue(string input)
{
var result = _values.FirstOrDefault(x => string.Compare(x.Value, input, true) == 0);
if (result.Equals(default(KeyValuePair<int,string>)))
{
return -1; // returns -1 if no matches are found
}
return result.Key;
}
}
I made a fiddle here, thanks #Ron for finding my midnight brain code flaw!
If you want dirt simple, just write a static helper class like this one:
public class CodeConverter
{
private static readonly string[] lookup = new []
{
"[Unknown]",
"Very Common",
"Common",
"Standard",
"Rare",
"Very Rare"
};
public static string CodeToString(int code)
{
if (code < 0 || code > lookup.GetUpperBound(0)) code = 0;
return lookup[code];
}
public static int StringToCode(string text)
{
int i = Array.IndexOf(lookup, text);
return Math.Min(0,i);
}
}
You can do something pretty simple, but you should break it into two methods. Having one method that does two things is really bad architecture.
public static class RarityConverter
{
private static List<Tuple<int, string>> Rarities = new List<Tuple<int, string>>()
{
new Tuple<int, string>(1, "Very Common"),
new Tuple<int, string>(2, "Common"),
new Tuple<int, string>(3, "Standard"),
new Tuple<int, string>(4, "Rare"),
new Tuple<int, string>(5, "Very Rare"),
};
public static string ToString(int rarity)
{
return Rarities.FirstOrDefault(t => t.Item1 == rarity)?.Item2;
}
public static int? ToInt(string rarity)
{
return Rarities.FirstOrDefault(t => string.Compare(t.Item2, rarity, true) == 0)?.Item1;
}
}
You could also use Enum's, but that would require you to use the DescriptionAttribute to decorate/convert the passed in string name to the enum name.
I would create a class that can store both values and then call on each value as needed.
public class Rarity
{
public Rarity(int numValue)
{
NumValue = numValue;
switch(numValue)
{
case 1:
StringValue = "Very Common";
break;
case 2:
StringValue = "Common";
break;
case 3:
StringValue = "Standard";
break;
case 4:
StringValue = "Rare";
break;
case 5:
StringValue = "Very Rare";
break;
default:
StringValue = "";
break;
}
}
public int NumValue { get; }
public string StringValue { get; }
}
As you load your CSV values you can initialize your class object (Rarity in my example) with the int value you mentioned.
Rarity rarity = new Rarity(my_csv_int_value);
Now you can grab which ever value you need at any time.
rarity.NumValue //1,2,3,4,5
rarity.StringValue //Very Common, Common, etc...
Probably about the same amount of code, but more versatile and you don't have to keep parsing out strings.
I recommend
enum, even with the extra decoration needs. The only other competing force for me is that data should live in data land, not in code land, so I would most probably not have these values explicitly in the code!
I do not recommend this exact approach or that of OP, I was answering the need for terseness
Your logic is already in string to string transformation land. Why not O(1) lookup both ways? You could have a two-way lookup/dictionary.
var lookup = new Dictionary<string, string>()
{
{ ”1”, "Very Common" },
{ “2”, "Common" },
{ “3”, "Standard" },
{ “4,” "Rare" },
{ “5”, "Very Rare" },
{ “Very Common”, “1” }
//etc iPhone editing sucks
};
You could even write out just the forward lookup half of the Dictionary and have an extension method or dedicated class ToTwoWayLookup fill in the reverse lookup part to not have to type 2x the values. (See the accepted answer for how to do a dictionary reverse lookup for method), you could also remove the ContainsKey check
Then in your function you get rid of the bool parameter and just do a lookup in this dictionary .I don’t know what the function name would be... FlipRepresentation?
I Would probably do this
Perhaps having a reverseLookup Dictionary separately would make more sense, so you can have two methods that have more meaningful names. Terseness is not all! Strive to make the code understandable to other humans! I would prefer reading ToNumerical(“Common”), ToNumberFromRarityName, ToRarityName(“1”) or ToRarityNameFromNumber rather than FlipRepresentation(‘1”) or ParseRarity(“1”, false);
I would probably not leave string<->string land for string<->int land like other suggest to save the call to int.Parse(val) when reading from the file.
This seems to be a standard this of values, if it was me I would simplify with this (depending on requirements I would either add range checking or error handling).
public static class Rarities
{
private static List<string> _rarityValues = new List<string>()
{
"Empty",
"Very Common",
"Common",
"Standard",
"Rare",
"Very Rare"
};
public static string ToRarityString(this int rarity)
{
return _rarityValues[rarity];
}
public static int ToRairityInt(this string rarity)
{
return _rarityValues.IndexOf(rarity);
}
}
and then you can call directly from the values:
var rarityInt = 1;
var rarityString = "Rare";
var stringValue = rarityInt.ToRarityString();
var intValue = rarityString.ToRairityInt();

C# - Get switch value if in default case

Help please, I have this case:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
// <HERE>
break;
}
As you can see the switch gets the value directly from a method without saving it as a variable.
Is it possible to get which value fires the default case?
For example if MyFoo() returns 7, how can I get that value?
I want to avoid to save the method result as a variable, is there a way to get the switch value from inside a case? Something like this:
default:
this.SwitchValue // <<--
break;
Thank you for reading,
~Saba
Is there a way to get the switch value from inside a case?
The only (proper) way is actually to store the result of MyFoo() in a variable.
var fooResult = MyFoo();
switch (fooResult)
{
case 0:
...
break;
...
default:
handleOthersCase(fooResult);
break;
}
This code is readable and understandable and have no extra cost (As #SheldonNeilson says: It's on the stack anyway).
Also, the MSDN first example about switch totally look like this. You can also find informations int the language specification.
You also can make your own switch based on a dictionary, but the only advantage I see is that you can use it for complex cases (any kind of object instead of string/int/...). Performance is a drawback.
It may look like this:
public class MySwitch<T> : Dictionary<T, Action<T>>
{
private Action<T> _defaultAction;
public void TryInvoke(T value)
{
Action<T> action;
if (TryGetValue(value, out action))
{
action(value);
}
else
{
var defaultAction = _defaultAction;
if (defaultAction != null)
{
defaultAction(value);
}
}
}
public void SetDefault(Action<T> defaultAction)
{
_defaultAction = defaultAction;
}
}
And be used like this:
var mySwitch = new MySwitch<int>();
mySwitch.Add(1, i => Console.WriteLine("one")); // print "one"
mySwitch.Add(2, i => Console.WriteLine("two")); // print "two"
mySwitch.SetDefault(i => Console.WriteLine("With the digits: {0}", i)); // print any other value with digits.
mySwitch.TryInvoke(42); // Output: "With the digits: 42"
Or based on this response, this:
public class MySwitch2<T>
{
private readonly T _input;
private bool _done = false;
private MySwitch2(T input)
{
_input = input;
}
public MySwitch2<T> On(T input)
{
return new MySwitch2<T>(input);
}
public MySwitch2<T> Case(T caseValue, Action<T> action)
{
if (!_done && Equals(_input, caseValue))
{
_done = true;
action(_input);
}
return this;
}
public void Default(Action<T> action)
{
if (!_done)
{
action(_input);
}
}
}
Can be used like that:
MySwitch2<int>.On(42)
.Case(1, i => Console.WriteLine("one"))
.Case(2, i => Console.WriteLine("two"))
.Default(i => Console.WriteLine("With the digits: {0}", i));
I can't see a reason as well why to use it like that but may be a work around will be like this:
int x;
switch ( x = MyFoo())
{
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
var s = x; // Access and play with x here
break;
}
No, this isn't possible.
You can assign the value to variable inside switch, if you want to look like reinventing the wheel:
int b;
.....
switch (b = MyFoo())
{
case 1:
break;
case 2:
break;
default:
//do smth with b
break;
}
The easiest way is to save the result of MyFoo() as a variable.. But if you don't want to do that you could do:
switch(MyFoo()){
case 0: //...
break;
case 1: //...
break;
case 2: //...
break;
default:
this.SwitchCase = MyFoo();
break;
}
Although I would advise against this and say save the value as a variable to save your program the extra work.
Saving the value of MyFoo as a variable becomes more important the more complex the example gets as the value of MyFoo could have changed between the switch and default case.
Also this will only work where MyFoo has no side-effects and obviously must always return the same value for any given parameter.
for example the following would work:
Private int MyFoo()
{
return 3;
}
But the following would not:
private int MyFoo()
{
Random r = new Random();
return r.Next(5);
}
This is possible now.
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#property-patterns
Example:
int? TryGetColumnIndex(string columnName)
=> GetValue(columnName)
switch
{ var result when result > -1 => result, _ => new int?() };
result will capture the result of GetValue.
Even cooler, you can do propery checks.
i.e instead of when result > -1 you can even say when result.ToString().Length > 2 and such.

Break tag inside of a method

I have a switch statement that executes some logic over and over. Rather then use cut and paste I wanted to put it into a function, but I am failing badly at this.
This is what I want to do, but it does not compile because the break tag in the function does not exist. Can anyone refactor this to a better working version?
switch(param.ToString())
{
case "1":
BreakIfNotArgumentType<B>(param);
//do stuff
break;
case "2":
BreakIfNotArgumentType<BF>(param);
//do stuff
break;
}
private T BreakIfNotArgumentType<T>(object argumentObject)
{
if (argumentObject is T)
{
return (T)argumentObject;
}
else
{
break;
}
}
Your function is essentially replicating the functionality of the as operator.
string foo = "foo";
....
object a = foo;
object b = 12;
....
string bar = a as string; // will give you "foo"
string zed = b as string; // returns null
The as operator functions as a runtime-safe cast. If the target instance can't be cast to the target type, then a null reference is assigned. Because of this, it will only work with reference types. The most common usage is like this...
string bar = a as string;
if(bar != null)
{
// do stuff
}
Because this gives the type checking and casting operation in one statement.
You should post your switch statement and we may be able to streamline it better. Trying to write a truly inline function as you had (where you were expecting it to substitute the code in the function into your switch statement, which makes it more of a macro than a function) won't work.
You could have the function return a null if the argument can't be cast or throw an exception for a couple of ideas on how to handle that part of the code.
private T BreakIfNotArgumentType<T>(object argumentObject)
{
if (argumentObject is T)
{
return (T)argumentObject;
}
else
{
return null;
}
}
Or
private T BreakIfNotArgumentType<T>(object argumentObject)
{
if (argumentObject is T)
{
return (T)argumentObject;
}
else
{
throw CustomException("Argument wasn't valid!");
}
}
Make your method to return a boolean and check the return value:
switch(param.ToString())
{
case "1":
if (CheckForArgumentType<B>(param))
{
// Do your cast here
param = (B)param
}
else
break;
case "2":
if (CheckForArgumentType<B>(param))
{
// Do your cast here
param = (B)param
}
else
break;
}
.................
private bool CheckForArgumentType<T>(object argumentObject)
{
return (argumentObject is T)
}
if you only have 2 values to compare with - use IF statement instead

Can't cast 2nd Enum value to int?

I don't get this. I was able to cast my first enum value to int but not the second?
public enum PayPalTransactionType
{
Authorization = 0, // Debit
Capture = 1, // Credit
Refund = 2,
Void = 3
}
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
string actionCode = string.Empty;
switch (payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
return actionCode;
}
on my 2nd case statement I get this casting error:
Cannot implicitly convert type int
to PayPalTransactionType. An
explicit conversion exists (are you
missing a cast?)
Why are you trying to cast in the first place? Just leave it as the enum value everywhere:
public string GetPayPalTransCode
(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
string actionCode = string.Empty;
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
return actionCode;
}
Additionally, I'd have an explicit default action for unrecognised codes, and just return directly:
public string GetPayPalTransCode
(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
return "Debit";
case PayPalServiceBase.PayPalTransactionType.Capture:
return "Credit";
default:
return ""; // Or throw an exception if this represents an error
}
}
Alternatively, you could use a Dictionary<PayPalTransactionType, string>.
Why are you casting to int at all? The thing you are switching on is already of the enum type!
As to the other part of the question, the reason the first cast is working is because an implicit cast from a constant int 0 to an enum type always works, whereas the other attempted cast is from a non-zero int value.
why for god's sake are you doing a cast??
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch (payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
}
bascially same type in here, isn't it?! you want to compare enum against enum, don't you?
just do
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
// ...
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
// ...
}
btw - it's not best practice to assign PayPalTransactionType.Authorization to 0. 0 should be used for parsing-fallbacks!
edit:
your code would be correct if you do
public string GetPayPalTransCode(PayPalServiceBase.PayPalTransactionType payPalTransactionType)
{
switch ((int)payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
break;
}
}
which is quite ...!
Remove the (int) casts in your case statements. The switch can handle the enum values.
Since the switch is on `PayPalTransactionType', values of that type should be used in the case statements.
You don't need these casts in the first place. Just make it case PayPalServiceBase.PayPalTransactionType.Authorization, etc.
Tim,
I am not a Java/C# expert, but here is my 2 cents on the code block above ...
If you're using an enum, why do you need to have an int value, if you do, then do something like:
public enum PayPalTransactionType
{
Authorization(0, Debit),
Capture(1, Credit),
Refund(3, null),
Void(4. null);
private final int code;
public int getCode()
{return(code);}
private PayPalTransactionType(final int code, final TransactionType transactionType)
{
this.code = code;
this.transactionType = transactionType;
}
private TransactionType getTransactionType()
{return(transactionType);}
}
public enum TransactionType
{
Credit("Funds are added to the specified account."),
Debit("funds are deducted from the specified account.");
private final String description;
public String getDescription()
{return(description);}
private TransactionType(final String description)
{this.description = description;}
}
Switches are useful for a very small amount of cases. You can simply do this:
final PayPalTransactionType payPalTransactionType = PayPalTransactionType.Authorization;// this is just an example of the parameter you'd be passing in.
payPalTransactionType.getTransactionType();// an emum is a static database, simply store other things that are related to this value.
Walter
It's not the cast to int that's giving you a problem. Its the cast of (int)PayPalServiceBase.PayPalTransactionType.Capture (which is an int) back to PayPalServiceBase.PayPalTransactionType that's the problem.
You don't need the casts to int. Just use the enum directly.
switch (payPalTransactionType)
{
case PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
The error occurs because your trying to implicitly convert payPalTransactionType to int. Maybe this will enlighten your problem:
switch ((int)payPalTransactionType)
{
case (int)PayPalServiceBase.PayPalTransactionType.Authorization:
actionCode = "Debit";
break;
case (int)PayPalServiceBase.PayPalTransactionType.Capture:
actionCode = "Credit";
break;
}
This first cast allows you to switch on ints instead of PayPalTransactionTypes. Since the switch statement supports enums, you don't need this cast.
Why are you casting it to an int the first place.? Just do the case statements using the enumerated type.
If you are really just looking up a string a better method would be an array of strings that you index by the enumerated type. That would be faster, less code and easier to maintain.
So something like this:
public enum PayPalTransactionType
{
Authorization = 0, // Debit
Capture = 1, // Credit
Refund = 2,
Void = 3,
Max // This must always be the last type and is used just as a marker.
}
string[] ActionCode = new string[(int)PayPalTransactionType.Max] { "Debit", "Credit", "Refund", "Void" };
public string GetPayPalTransCode(PayPalTransactionType payPalTransactionType)
{
return ActionCode[(int)payPalTransactionType];
}

Categories

Resources