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
Related
I want to check if a given object value is null or is an empty string. I got the following ideas:
...
public void Cmp1(object a) {
if(a == null || Equals(a, string.Empty)) {
Value = null;
return;
}
....
}
public void Cmp2(object a) {
if(a == null || (a is string stringValue && string.IsNullOrEmpty(stringValue))) {
Value = null;
return;
}
....
}
Which one is better? Is Equals exposing some danger? Or (a is string stringValue && string.IsNullOrEmpty(stringValue)) is super slow?
The problem with the second option is you almost certainly want to use stringValue after the conditional block, meaning you must do the work a second time.
I might use the as operator, like this:
public void Cmp(object a)
{
var stringValue = a as string;
if (string.IsNullOrEmpty(stringValue)) {
Value = null; //this suggests the function should return something, instead of a void method
return;
}
// ...
}
Or I might negate the condition (and remove the null check):
public void Cmp(object a) {
// pattern matching is still safe to use if `a` is null
if(a is string stringValue && !string.IsNullOrEmpty(stringValue)) {
// stringValue is in scope here
}
else {
// but not here... but we no longer need it
Value = null;
}
}
If you don't intend to use stringValue again at all, I'd write it like this:
public void Cmp(object a)
{
if (!(a is string) || string.IsNullOrEmpty((string) a)) {
Value = null;
return;
}
// ...
}
But most of all... none of this is likely to drive the performance of your program. You're spending a bunch of time worrying about details that would be much better spent looking at profiler results, which can tell you exactly where to spend your time optimizing to make your app faster.
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'm new to C# and I'm trying to figure out the best way to test if a method returns correctly, ie; did the method get the information I wanted.
It's the types that are making this difficult. Is there a way that I can sometimes return bool and sometimes return something else?
In PHP I would create my function like this
function myFunc(){
//Do Stuff
if(/*whatever*/) return (string) "abcdefg";
return false; //otherwise it will just return false
}
Then call it like this to test if it worked or not
if(!$var=myFunc()) die("It Didn't Work");
echo $var;
But with C#, my function has to return a specified type, not a string or bool false if it didn't work out.
If in C# I have a method that returns IntPtr I could have it return (IntPtr) 0 instead of false, but this is messy and there's probably a better way of doing it.
Any Ideas? What's the standard and usual way of doing this in C#?
There are typically two approaches here:
Use Exceptions
Use the TryXXX approach.
The appropriate method depends on what this is doing. If the "false" case is really something that's exceptional and not the norm, raising an exception is an appropriate way of handling it.
If, however, you're doing something like parsing user input, where its common that you'll "fail", using the TryXXX approach is a good example. This would look like:
bool TryMyFunc(out string result)
{
if (...)
{
result = "abcdefg";
return true;
}
result = string.Empty;
return false;
}
This is how Int32.TryParse works in the framework, for example.
You can always return null.
string Foo()
{
if (!success) return null;
return "abcd";
}
You then check the call like that:
var tmp = Foo();
if (tmp == null) return -1;
// tmp is a string so do your work
The null return will only work with object, unfortunately you can't do that with an int. In that case throw an exception or use a nullable int:
int? Bar()
In your example I would return null from your function in C#:
public string myFunc(){
//Do Stuff
if(/*whatever*/) return "abcdefg";
return null;
}
And then in your calling code:
string myVar = myFunc();
if(null != myVar)
{
throw new Exception();
}
Console.WriteLine(myVar);
It should be noted though that any time you throw exceptions for non-exceptional circumstances (meaning, if your call to myFunc could, in reasonable usage, return null) you will take a serious performance hit. It takes a long time to generate an exception, so it's generally better to avoid them, perhaps by using a pre-requisite check before even calling myFunc.
In circumstances where you're dealing with non-nullable value types, C# has a concept called Nullable Types.
If your Intention is how to return types you can use Tuple<>
public Tuple<string,bool> myFunc()
{
//Do Stuff
if(/*whatever*/) return (string) new Tuple<string,bool>("abcdefg",true);
return new Tuple<string,bool>(null,false);
}
Use Exception based programming:
public string Blah()
{
if (whatever)
{
return "abcdefg";
}
throw new Exception("Something went wrong");
}
Or you could return null or string.Empty
Personally, I prefer use null.
public string foo()
{
if (whatever)
{
return "abc";
}
return null;
}
and Then:
if(foo() != null)
{
//do something
}
else
{
// *It Didn't Work*
}
My code is like the below one,
public object GetObjectValue(object obj, int condition)
{
if(condition > 10)
{
//exit from method
// return; gives compiler error.
}
else
{
GetObjectValue(obj,condition); // like this i need to use recursive call.
//Do stuffs
}
}
How to exit from this method. Help me.
Some points:
You need to return something in either case. Even if you return null on if(condition > 10), your next compilation error will say you need to return a value on every path (actually, that's the same compilation error)
GetObjectValue(obj,condition); may result in an infinite recursion - you call it with the same values over and over.
You cannot "do stuff" after a return statement - that marks the end of the executed code (unless you have a finally block, but that's another subject). If you don't want to return that value that's also great, but you probably want to use it somehow: object returnedValue = GetObjectValue(obj, condition);
You may be looking for something like:
public object GetObjectValue(object obj, int condition)
{
if(condition > 10)
{
//exit from method
return null;
}
else
{
IChild current = (IChild)obj
//Do stuffs HERE
return GetObjectValue(current.Parent, condition + 1); recursive call.
}
}
You need to return an object reference, or null.
public object GetObjectValue(object obj, int condition) {
if (condition > 10) {
return null;
} else {
return GetObjectValue(obj, condition);
}
}
Be aware though, that this method is very prone to a stack overflow error because any value of condition less than or equal to 10 will never reach the base case, or terminating condition. Recursive methods need a case that returns a value without calling itself.
public object GetObjectValue(object obj, int condition) {
if (condition > 10) {
return null;
} else {
return GetObjectValue(obj, condition++);
}
}
Now condition is incremented, so when the method is called, it will eventually progress towards a value greater than 10, satisfying the condition and returning null. This is still a useless method though, because it can only ever return the same value for any input; the only difference will be how many recursive calls it makes before returning null.
You are supposed to return an object:
public object GetObjectValue(object obj, int condition)
Either change the return type:
public void GetObjectValue(object obj, int condition)
Or use a valid return statement:
if(condition > 10)
{
//exit from method
return null;
}
You have specified the return type as object, so have to specify the valid return type. Try the below code change,
public object GetObjectValue(object obj, int condition)
{
if (condition <= 10)
{
GetObjectValue(obj, condition);
}
return null; //return whatever object you have to return
}
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];
}