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];
}
Related
I'm learning c# so sorry for the stupid question. Here is my code:
Random prekey = new Random();
string[] firstname = {"Александр", "Михаил", "Иван", "Максим", "Артем", "Даниил", "Дмитрий", "Кирилл", "Андрей", "Егор"};
string[] secondname = { "Александов", "Михайлов", "Иванов", "Максимов", "Артемов", "Даниилов", "Дмитров", "Кириллов", "Андреев", "Егоров" };
string fullname = firstname[prekey.Next(0, 10)] + " " + secondname[prekey.Next(0, 10)];
int a = prekey.Next(0, 3);
//string introduce;
switch (a)
{
case 0:
string introduce = firstname[prekey.Next(0, 10)];
break;
case 1:
string introduce = secondname[prekey.Next(0, 10)];
break;
case 2:
string introduce = fullname;
break;
}
As you can see, my plan is to have the "introduce" randomly be either "firstname" or "secondname" or both. But I am facing the error "A local variable named 'introduce' is already defined in this scope". I searched and found this question: C# : error using if/switch : "Local variable already defined in this scope" but the answers didn't help me. For example, I tried to declare a variable before the switch, but nothing changed. So I just removed that line as a comment. One day I will try to use "if", but now I want to use switch. I posted my calculator here before, here it is again:
static void Main(string[] args)
{
void MyMet(double? Result = null)
{
string[] calc = Console.ReadLine().Split(' ');
double a = Result ?? double.Parse(calc[0]);
char b = char.Parse(calc[1]);
double c = double.Parse(calc[2]);
switch (b)
{
case '*':
Result = a * c;
break;
case '+':
Result = a + c;
break;
case '-':
Result = a - c;
break;
case '/':
Result = a / c;
break;
}
Console.Write(Result);
MyMet(Result);
}
MyMet();
}
In this case, everything works, but here the variable is declared with question marks (to be honest, I have no idea how they work, this part was just copied) and I tried to recreate it exactly in the current case, but apparently C# does not wants to treat string as double, so he just wrote "Nullable reference types are not available in C# 7.3. Please use language version 8.0 or higher." Can I solve this problem by continuing to use the switch and not switching to another version?
You need to declare the variable only once, before it is used.
When you assign the variable (as opposed to declaring it) you do not specify the type to the left of the variable name.
string introduce;
switch (a)
{
case 0:
introduce = firstname[prekey.Next(0, 10)];
break;
case 1:
introduce = secondname[prekey.Next(0, 10)];
break;
case 2:
introduce = fullname;
break;
}
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();
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.
I want to use a generic WriteList(List value) function to write a List using the BinaryWriter. Here is the code I am using:
public void WriteList<T>(List<T> value)
{
for (int i = 0; i < value.Count; i++)
{
_writer.Write(value[i]);
}
}
The error I am receiving is:
Error 1 The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments
Error 2 Argument 1: cannot convert from 'T' to 'bool'
The BinaryFormatter is absolutely not an option.
I really don't think you can avoid BinaryFormatter. Because type T can be any complex type and each instance of T can represent a huge graph of variables on memory.
so the only solution you have is to convert your instance of T to the byte[] format and the simplest solution for that is: BinaryFormatter
Actually the reason .Write() method only accept primitive types is that it knows how to convert them directly to byte[] (using Convert.ToXXX()) but there is no way it could guess that for generic type T.
As a work around you can define an interface like this:
public interface IBinarySerializable
{
byte[] GetBytes();
}
and then implement it in your class:
public class MyClass: IBinarySerializable
{
public int X {get;set;}
public byte[] GetBytes()
{
return BitConverter.GetBytes(X); // and anyother
}
}
and change your method to this:
public void WriteList<T>(List<T> value) where T:IBinarySerializable
{
for (int i = 0; i < value.Count; i++)
{
_writer.Write(value[i].GetBytes());
}
}
If you check out the docs for BinaryWriter you'll see it doesnt accept an argument of object (Writes primitive types), and the compiler is trying its best at an overload, and failing, since you can't cast your T to bool, or anything else that BinarwWriter would like.
You're going to have to convert your object into something the BinaryWriter will work with.
You can't pass a generic T to BinaryWriter.Write - it has overloads for many specific types (bool, byte, byte[], int, string, etc), but no generic one. So you'll need to do it yourself, in some way similar to the code below.
public void WriteList<T>(List<T> value)
{
for (int i = 0; i < value.Count; i++)
{
switch (Type.GetTypeCode(typeof(T))){
//_writer.Write(value[i]);
case TypeCode.Boolean:
_writer.Write((bool)(object)value[i]);
break;
case TypeCode.Byte:
_writer.Write((byte)(object)value[i]);
break;
case TypeCode.Char:
_writer.Write((char)(object)value[i]);
break;
case TypeCode.Decimal:
_writer.Write((decimal)(object)value[i]);
break;
case TypeCode.Double:
_writer.Write((double)(object)value[i]);
break;
case TypeCode.Single:
_writer.Write((float)(object)value[i]);
break;
case TypeCode.Int16:
_writer.Write((short)(object)value[i]);
break;
case TypeCode.Int32:
_writer.Write((int)(object)value[i]);
break;
case TypeCode.Int64:
_writer.Write((short)(object)value[i]);
break;
case TypeCode.String:
_writer.Write((string)(object)value[i]);
break;
case TypeCode.SByte:
_writer.Write((sbyte)(object)value[i]);
break;
case TypeCode.UInt16:
_writer.Write((ushort)(object)value[i]);
break;
case TypeCode.UInt32:
_writer.Write((uint)(object)value[i]);
break;
case TypeCode.UInt64:
_writer.Write((ulong)(object)value[i]);
break;
default:
if (typeof(T) == typeof(byte[]))
{
_writer.Write((byte[])(object)value[i]);
}
else if (typeof(T) == typeof(char[]))
{
_writer.Write((char[])(object)value[i]);
}
else
{
throw new ArgumentException("List type not supported");
}
break;
}
}
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