In a pre-sorted List<int> I am about to find the last element that satisfies the condition such as int lastScore = list.Last(x => x < 100). If there is no element(s) in the list that satisfies this condition, an InvalidOperationException is thrown with the error message: Sequence contains no matching element. This happens with list.First(...) too.
I even tried to make lastScore nullable to no avail.
Is catching the exception and manually assigning lastScore to null the only way out?
Use FirstOrDefault or LastOrDefault to get null if there is no match, assuming you are working with reference types. These methods will return the default value for value types.
I would probably just catch the Exception at the closest-point of use.
This is because LastOrDefault/FirstOrDefault over an IEnumerable<int> will return 0 (the default for an int), which may be a "valid" value - this depends on the actual context and defined rules. While converting the sequence to an IEnumerable<int?> would allow the previous methods to return null, that seems like more work than it is worth.
If needing to use lastScore on a continued use, consider:
int? lastScore; /* Using a Nullable<int> to be able to detect "not found" */
try {
lastScore = list.Last(x => x < 100); /* int -> int? OK */
} catch (InvalidOperationException) {
lastScore = null; /* If 0 see LastOrDefault as suggested;
otherwise react appropriately with a sentinel/flag/etc */
}
if (lastScore.HasValue) {
/* Found value meeting conditions */
}
Or if able to discard the case when it isn't found, consider:
try {
var lastScore = list.Last(x => x < 100);
/* Do something small/immediate that won't throw
an InvalidOperationException, or wrap it in it's own catch */
return lastScore * bonus;
} catch (InvalidOperationException) {
/* Do something else entirely, lastScore is never available */
return -1;
}
Related
So, I've been having a little bit of an argument with a fellow coder lately. Specifically: We've been arguing about the proper use of Try / Catch and If / Else as well as First() / Single() in a specific scenario.
Variation #1 - His approach
var items = Search(dto.number); // Returns a List of Objects
if (items.Count = 1)
{
wPerson = items.First();
}
else
{
return;
}
Variation #2 - I changed his code to this.
var items = Search(dto.number); // Returns a List of Objects
try
{
wPerson = items.Single();
}
catch
{
// Handle exception
return;
}
We expect the result of var items = Search(dto.number); to always be 1.
The Question:
Which changes were nescessary? I am trying to defend my point of view below. Please correct me.
First of all: The Single(). I always try to be as specific as possible and I decided on the following rules:
First --> Accepts N
FirstOrDefault --> Accepts 0 and N
Single --> Accepts 1
SingleOrDefault --> Accepts 0 and 1
First() may have worked but it wasn't 100% specific, so I considered it wrong since we had an option to be even more specific.
Secondly: Try / Catch vs If / Else. Since I had already changed First() to Single(), I considered the if statement to be redundant. Yes. I know that Try / Catch is less performant than the If statement but we expect to have NOTHING BUT 1 result. And if we get more or less, I expect it to be a mistake and with Try / Catch I'd actually treat it that way.
Am I so off here?
Well, throwing / catching exceptions is for exceptional situation only, so your current code
try {
wPerson = items.Single();
}
catch {
// Something is very wrong (e.g. RDBMS table's ruined, file's corrupted etc)
throw;
}
means that you expect one and only one wPerson in items. If, however, 0, 1, or 2 item in items is expected behaviour
you should not use Single, but, say, Take
var items = Search(dto.number); // Returns a List of Objects
var wPersons = items.Take(2).ToArray();
if (wPersons.Length <= 0) {
// No person found; probably, wPerson = some_default_value
...
}
else if (wPersons.Length == 1) {
// Exactly one person found
wPerson = wPersons[0];
...
}
else {
// Two or more persons found; we have to resolve tie somehow
...
}
Don't try/catch if you can avoid it. An exception should be used to "exceptional flow", iE: not to be expected.
However I'd suggest you combine both of the variations.
var items = Search(dto.number); // Returns a List of Objects
if (items.Count != 1) return;
wPerson = items.Single();
Since you expect only 1 result if successful, you can immediately break.
If, for any reason, you change your code and there are x > 1 items this method will break since you only expect 1 (hence the Single) and not go into an "unexceptional" flow (assuming the First object is the correct object)
I have the below function that iterates over a list of workers, invoking their DoStuff() method. If the first worker fails, I try the next one until I'm out of workers. If they all fail, I re-throw the last exception.
// workers is an IList<>.
public object TryDoStuff()
{
for (int i = 0; i < workers.Count; i++)
{
try
{
return worker[i].DoStuff();
}
catch
{
if (i == workers.Count - 1)
{
throw; // This preserves the stack trace
}
else
{
continue; // Try the next worker
}
}
}
}
When compiling, I get an error that "not all code paths return a value" for this function. Although I can silence the error by adding an explicit return after the for loop, I'm doubting the compiler is accurate here as I don't see how the for loop will be escaped without either returning or re-throwing an exception. And if an exception is re-thrown, not returning a value is valid.
What am I missing? Is csc unable to reason about the conditional in the catch block?
Yes
If there is an exception thrown on the last index and count isn't what you expect it to be (unlikely yet possible)
Or as RAM pointed out if Count is zero
In this case, the static analysis and subsequent compiler error is very justified
As previously mentioned, if workers is empty (Count is 0), there's no valid return path.
There's also another race condition (depending on the full context, obviously) where workers is not empty, an exception is thrown on an element, there are still elements to iterate in workers, but after evaluating if (i == workers.Count - 1) and before the continue statement executes, another thread removes elements from workers (or changes the entire workers variable to a new instance).
In that scenario, the for condition will return false on the next iteration unexpectedly and you'll fall out of the loop with no return statement for the method.
public object TryDoStuff()
{
for (int i = 0; i < workers.Count; i++)
{
try
{
return worker[i].DoStuff();
}
catch
{
if (i == workers.Count - 1)
{
throw; // This preserves the stack trace
}
else
{
// XXX If workers is changed by another thread here. XXX
continue; // Try the next worker
}
}
}
}
I wrote as a comment for you:
What will be happen if the count of the workers list items be
zero?
It seems this is the compiler question and it dose not do more research about your code! :)
Actually this reason is enough for compiler to show the bellow error to you
not all code paths return a value
When the compiler encounters with a loop in the whole of the body of a method it assume that the loop condition cause that the loop body be ignored then it expected any value out of the loop too.
Yes, even if we set the condition of the loop at the way that the loop be executed!
Proof:
With error:
public static object TryDoStuff()
{
var result =0;
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Add 100 unit");
result += 100;
return result;
}
//Console.WriteLine("last line");
// return result;
}
Without error:
public static object TryDoStuff()
{
var result =0;
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Add 100 unit");
result += 100;
// return result; you can un-comment this line too
}
Console.WriteLine("last line");
return result;
}
I sometimes run into situations where, if a line of code throws an exception, I don't care what the exception is or why it was thrown; I just need to take a generic action and move on. For example:
try
{
// Throws IndexOutOfRangeException when DB field
// is null in the current record
Template = record.GetString(MYSQL_IDX_TEMPLATE);
}
catch
{
Template = FIELD_UNAVAILABLE;
}
I was wondering if there's a short-hand way to set a value based on a generic try/catch?
I'm thinking of something similar to ternary syntax:
string blah = (index >= ubound ? "No more records" : "records exist");
please help. I am a begginner at c# but have programed in python before. My problem is that the their is an error which says, Severity 'Program.Sqrt(int)': not all code paths return a value. Please help, i have include a return value and have used an if and else statement.
using System;
namespace helloworld
{
class Program
{
static void Main(string[] args)
{
}
float Sqrt(int x)
{
Console.WriteLine("please enter your number to be square rooted");
string l = Console.ReadLine();
x = Convert.ToInt32(l);
float num = 1;
if (num * num != x)
{
num++;
}
if (num * num == x)
{
return num;
}
else
{
Console.WriteLine("FAILED TO EXECUTE");
}
}
}
}
So this is kinda just C# Basics - well.. programming basics...
If you declare your method as a 'type' of return value other than void, then it expects you to use the keyword 'return' at some stage.
You have created a method called:
float Sqrt(int x)
This indicates that it MUST return a float value.
I can see that in some cases (if statements) you are doing a
return num;
But look carefully. in the other if statements, there is no return statement - so basically, in the else statement it will get stuck.
In order to make sure that your method does not get stuck - you should make sure that it has the possibility of returning either a valid value, or it throws an exception.
if (num * num == x)
{
return num;
}
else
{
throw new Exception("Unable to execute");
}
The most important part of the compiler error you are receiving is that a method with a declared return type must always return a value of that type, or throw an error.
Let's take a look:
float Sqrt(int x)
{
// Your code here
}
What we've just done is declared a method called Sqrt that accepts a single int parameter called x. By using the float type at the beginning of the method, we're stating that this method always returns a float.
In your method body, you must return a float or throw an error. Let's take a look at a simple case.
float Sqrt(int x)
{
if (x > 0)
{
// Calculate square root
return Math.Sqrt(x);
}
else
{
// Ignore imaginary numbers for now, use absolute value
return Math.Sqrt(Math.Abs(x));
}
}
The above code works because both the if and else return a valid value. Your code is failing because your else doesn't return anything; see this simplified example:
float Sqrt(int x)
{
if (x > 0)
{
// Calculate square root
return Math.Sqrt(x);
}
else
{
// Ignore imaginary numbers for now, use absolute value
Console.WriteLine("Don't do that!");
// Note there is no return statement here
}
}
The above example fails, because the else doesn't return anything nor does it throw an exception. Another way to hand this is to throw an appropriate exception:
float Sqrt(int x)
{
if (x > 0)
{
// Calculate square root
return Math.Sqrt(x);
}
else
{
// Ignore imaginary numbers for now, use absolute value
throw new System.ArgumentException("x must be greater than 0");
}
}
The above example them assumes your code knows how to handle an exception. In the if else section, you can perform your logic but you have to return a float value or throw an exception of some kind.
As the error clearly stated, not all code paths return a value, and this will throw an exception.
if (num * num == x)
{
return num; //Okay
}
else
{
Console.WriteLine("FAILED TO EXECUTE");
//returns nothing here
}
To fix this, simply add a return statement after your Console.WriteLine returning what you'd want if the previous condition fails.
.NET compiler expects return statement in all possible scenarios of a function. If code fails that, it returns compilation error.
You could either return some error OR non-possible value in else block. Since in your code, else is not returning any value/exception, it gives an error.
I have a listView in my app. I loop through the items to check which one is currently selected and then return a value. As all paths have to return a value I have to return a value outside the loop which overwrites the for loop return, how do I keep this without overwriting it after the loop?
public string GetItemValue()
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Checked == true)
{
return listView1.Items[i].Text; // I want to keep this value
}
}
// Without overwriting it with this but the compiler
// requires me to return a value here
return "Error";
}
Any help is most appreciated. Thanks.
P.S I have tried using break after the if but no luck.
On edit: bringing down my comment from above.
You don't need to worry about this. As soon as it hits the first return inside the loop, it will return immediately with that value. No code outside the loop is ever hit in that case.
Incidentally, this code would be cleaner:
public string GetItemValue()
{
foreach (var item in listView1.Items)
{
if (item.Checked) return item.Text;
}
throw new InvalidOperationException("No checked items found");
}
Exceptions are a more idiomatic way of handling errors, and the foreach loop is preferred to a for loop when you're just iterating over collections.
Also using LINQ, you can get even more concise:
public string GetItemValue()
{
return listView1.Items.Cast<ListViewItem>().Single(i => i.Checked).Text;
}
Well, your return outside of the loop, return "Error"; shouldn't get called based on your logic. Since return causes your method to immediately exit, the "Error" return will never happen, that is unless the code never steps into the if inside the loop.
All things considered, this may be an exceptional case in your code. Thus, throwing an exception may be the appropriate thing to do:
public string GetItemValue()
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Checked == true)
{
return listView1.Items[i].Text; // I want to keep this value
}
}
throw new InvalidOperationException("Did not find value expected.");
}
Exceptions are usually thrown to indicate that a bug exists in code. A "Hey, that should really not be happening." The application stops, and hopefully the user gets an opportunity to contact support to help you reproduce it.
Based on your comment:
When I run it, it just returns the error text...
That means your check in your if statement is not succeeding.
if (listView1.Items[i].Checked == true)
Which means that none of your items in your ListView are checked.
That's the kind of situations where you are probably better of throwing an exception in order to signal the exceptional situation:
public string GetItemValue()
{
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Checked == true)
{
// Here you are leaving the GetItemValue method
// and the loop stops
return listView1.Items[i].Text;
}
}
// if we get that far it means that none of the items of
// the select list was actually checked => we are better of
// reporting this to the caller of the method
throw new Exception("Please select a value");
}
The return in your for loop isn't overwritten -- the method will return the value in the loop if your conditions are met. Execution of the method ends immediately upon reaching a return statement.
If your method is returning "Error", then I'd recommend looking at your code in a debugger, because it's reaching the end of the loop and returning the value "Error".
If you're returning a value in the loop, it should not reach the return that's outside of the loop. I would check to make sure that the loop is finding the selected item.
The other option is to create a local variable to hold the return value:
string returnValue = "Error";
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Checked == true)
{
returnValue = listView1.Items[i].Text;
break;
}
}
return returnValue;
Lastly, you might also consider returning an exception when no selections are found, and handling the exception from the calling method.
The return "Error" bit will not overwrite your loop return value. When a return is hit, the function exits, so when a value that is selected is found, the function will spit out your data and stop.
The compiler requires that all paths of the function return a value. The compiler cannot know before hand whether your inner loop if condition will be met. You can cache the value at a variable and return this in the end of the function e.g. :
public string GetItemValue()
{
string temp = null;
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].Checked == true)
{
temp = listView1.Items[i].Text; // I want to keep this value
break;
}
}
return temp; // Without overwriting it with this but the compiler requires me to return a value here
}
Actually, there is no need for a loop here:
return (listView1.SelectedItems.Count > 0)
? listView1.SelectedItems[0].Text
: "Error";
But, as it was said, the original question is misleading since return does not override values. You might be thinking about assignment, instead of return. In this case a working code can look like this:
string ret = "Error";
foreach(var item in listView1.Items)
{
if(item.Checked) { ret = item.Text; break; }
}
return ret;