crmFactory.RegisterDemoAccount throws Exception. In order to use the variable res I need to initialize it.
Since AccountRegistrationResponse is not initializable, how can I declare res without getting compilation errors about using unassigned variables?
I can assign it to null, but I don't think this is a good programming approach.
AccountRegistrationResponse res /*=null*/;
try
{
res = crmFactory.RegisterDemoAccount(CrmConfigRepository.CrmOwnerUserId
, CrmConfigRepository.CrmOrganizationName
, CrmConfigRepository.CrmBusinessUnitName
, demo.getData());
}
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
}
_log.Debug(res.getString());
You shouldn't try to continue your method after catching an unknown exception. Anything could have gone wrong and it makes no sense to assume that it's safe to continue. Only bad things can happen if you try.
Either return an error result, or better, just rethrow the original exception:
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
throw;
}
Now the compiler can see that res will always be assigned after the try block completes successfully.
I understand your reluctance to assign res to null - it feels pointless, and therefore wrong. It is a common approach in situations like this, though, when an object is needed outside the block in which it's assigned. Assuming you're doing the right thing in assigning your variable in a try/catch block (and it's not an uncommon pattern, in many cases), I wouldn't worry about it.
However, what would happen if the assignment failed? The second logging call would try to dereference res, and throw a NullReferenceException. That's not good.
You need to put the logging line inside the try/catch so that the compiler knows that res has been initialised.
try
{
res = ...
_log.Debug(res.getString()); }
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
}
It's THE right approach. Only thing, if null is a valid return value of RegisterDemoAccount, you could add a bool initialized = false that you set to true just after the RegisterDemoAccount.
Assign it to null, like you said, if you need it outside of try/catch. It's not bad way of programming.
but I don't think this is a good programming approach.
Why? If you don't initialise res and then RegisterDemoAccount(...) (or another expression before it) throws then res will not be assigned in the try statement.
Therefore execution could reach the final statement (after the catch block) with res unassigned.
The problem is the use of res in that last statement – the compiler can see it can get to this point without initialisation.
Related
In order to streamline my try blocks, I've made a static function to handle error catching because I was already catching errors the same way in all my methods anyway.
static class Exceptional
{
public static Exception Try(Action action, [CallerMemberName] string cmn = "")
{
try
{
action();
return null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace, cmn + ": " + ex.GetType().Name);
return ex;
}
}
}
And then I've replaced all cases of
try
{
...
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
}
with
Exceptional.Try(() =>
{
...
});
This not only streamlines wrapping my code in try blocks but also gives me a centralized place to globally change the way I'm handling exceptions.
I know it's not good practice to catch all exceptions and treat them all the same. I understand I'm only supposed to catch the types of exceptions I'm expecting to be thrown, but right now I'm just testing things and I don't know what's going to be thrown so I've been using try blocks to make sure I don't get silent or unexplained failures. And that's not what my question is about.
I'd like to know if I'm in danger of changing my code's behavior by doing this. Obviously the call stack is being changed by inserting an additional function into it, but can this extra function potentially cause unexpected issues? Critiques are welcome! Thank you.
EDIT: I should mention that I'm currently wrapping entire method bodies in my Exceptional.Try calls, so I'm particularly interested in knowing if I might encounter strange behavior in that case rather than if something outside the lambda expression might cause strange behavior.
It will work. It will also change the way your code behaves. Here's a test method:
[TestMethod]
public void TestMethod1()
{
int output = 0;
Exceptional.Try(() => output = 2 + 2);
Assert.AreEqual(4, output);
}
But here are some of the problems you get with that:
Code execution doesn't automatically stop if an exception is thrown. For example, you could do this:
Exceptional.Try(() => DoSomethingThatThrowsAnException());
And unless you declare another variable to hold the return value (exception or null) you don't know if anything went wrong (assuming the MessageBox is just for testing.) So it takes the predictable behavior of C# and turns it into something unpredictable. Someone would have to inspect that class to see what's happening when they execute their method. So you're now writing a try/catch but you have to follow a new convention, checking the return value of the exception. And unlike the default behavior, if you forget to check then your exceptions are never raised.
I had to declare the output variable separately and initialize it, even though I'm going to assign another value to it later. That's because I can't just do var output = 2 + 2. If I just declare it without initializing then when I try to use the value later the compiler complains that the variable may not be initialized. That's because it doesn't know whether the action is executing immediately or later (or ever.)
The default behavior of exceptions and try/catch is good and everyone understands it, so I wouldn't recommend doing anything to change it. If an exception happens then execution should be transferred to an exception handler or raised to the calling method.
I recommend taking a look at interceptors. They provide a way to keep exception handling separate from your code.
That should work fine. As you alluded to, the extra function call will show up in the call stack, but that should hardly be confusing to anyone.
A couple suggestions... the ToString() method returns all of the info you're looking for as well as any inner-exceptions. And I don't see a need to return the exception type unless you want to.
public static void Try(Action action, [CallerMemberName] string cmn = "")
{
try
{
action();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
This is specific to .NET
I am writing a code piece where I have to use catch all exception handler. I call a series of function which may return null. I do not want to continue if any of them return null as I have an alternate but costly method to get the same result. I want to know if I should be using the series of null checks or not.
My code looks something like:
var some_info = null;
try{
var a = GetA();
if(a != null){
var b = a.GetB();
if(b != null){
var c = GetC(b);
if(c != null){
some_info = c.GetSomeInfo();
}
}
}
catch(Exception e){
// cant do anything here but I need above code to be silent
}
if(some_info == null)
some_info = GetSomeInfoFromHeavyMethod();
in C# if we try to use null reference it throws an exception so if any of the variables above will be null a NullReferenceException will be thrown. Therefore we can write the above code like
var some_info = null;
try{
var a = GetA();
var b = a.GetB();
var c = GetC(b);
some_info = c.GetSomeInfo();
}
catch(Exception e){
// cant do anything here but I need above code to be silent
}
if(some_info == null)
some_info = GetSomeInfoFromHeavyMethod();
My question is, should I use null checks here or let exception handler work here? My gut feeling says I should use the null check as it is good practice but, I have a doubt as I have to use catch all exception handler here and I already have to bear cost of try/catch block.
Yes, I would strongly advise using null checks:
It shows that you expect that the values can be null, and that that in itself is not a problem
If you ever add logging in your catch block, you can easily do so without being spammed by easily-avoidable messages
When debugging the code, you really don't want to end up with the debugger stopping for a NullReferenceException due to just not doing checks
You say that you "already have to bear cost of try/catch block" - it's not clear whether you're talking about the code readability cost or performance cost, but there's basically no performance cost for a try/catch block if no exception is thrown. Compare that with the case when an exception is thrown, which definitely has performance implications.
Ultimately, I'd consider every NullReferenceException to be a bug somewhere - it's the kind of exception that should always cause you to either add more validation (e.g. to throw ArgumentNullException) or handle the value being null. That wouldn't the case in your code.
With some refactoring you may be able to use the null-conditional operator introduced in C# 6 to reduce the code though. You might end up with:
someInfo = GetA()?.GetB()?.GetC()?.GetSomeInfo();
Exceptions are supposed to be thrown when exceptional situations occur. So, it all depends on whether you want to consider the case of a function returning null exceptional or not. There is no hard rule.
Though I would suspect that if the functions are returning null instead of throwing an exception, then a certain choice has already been made, by those who implemented those functions, that the situation is not exceptional. But of course at the place where you call these functions you may want to redefine what is exceptional and what isn't.
There is, however, a little technical issue: throwing an exception is extremely know on Microsoft's implementation of C#, (possibly also on Mono? I don't know) so we unfortunately tend to favor not considering certain situations exceptional (and therefore not throwing an exception) when the choice is borderline and performance is an issue.
I wonder if someone could give me some advice please?
I need to check for the existence of some session variables in asp.net so for instance:
try
{
zOrder = Session["epdqOrderNo"].ToString();
zAmount = Session["epdqAmount"].ToString();
zEmail = Session["epdqEmail"].ToString();
}
catch
{
}
Some or all of the session variables may exist and I'm trying to check them all but it appears that the try/catch routine goes into the catch on the first exception that it finds. So in the above example if the session variable epdqAmount doesn't exist it won't try and check for epdqEmail as its already fell out the try part. So my question is is there any way to stop this behaviour and check all of the variables or should I be using something else?
You're getting the error because Session["foo"] will return null is there is no session state variable called foo, and you can't call ToString() on a null reference.
However, you can use Convert.ToString on a null reference (in which case it will simply return string.Empty), so you could try this instead:
zOrder = Convert.ToString(Session["epdqOrderNo"]);
zAmount = Convert.ToString(Session["epdqAmount"]);
zEmail = Convert.ToString(Session["epdqEmail"]);
Using this approach, no try...catch is required because exceptions won't get thrown if any of the session variables don't exist.
You generally shouldn't try...catch in this manner, you could be potentially hiding other problems in your code. Whenever you use a try...catch try to be more specific with the exception it is you are after e.g.
try
{
}
catch (ErrorICanHandle ex)
{
}
Although in your case you would be listening for a NullReferenceException which is an indicator that you should really be checking that directly in the code as you would be effectively using exceptions to control your application flow which isn't a good idea.
As to your code, assuming all your session values are of type string then all you need is a straight cast
zOrder = (string)Session["epdqOrderNo"];
zAmount = (string)Session["epdqAmount"];
zEmail = (string)Session["epdqEmail"];
string is a special type of value type which inherits from object so this would just leave your variable as null if there is nothing in the session and not throw an exception.
try this
if(Session["MyDataSet"] == null)
{//something}
else
{//something}
In general, you'd write 3 try/catch blocks.
Couple of notes though:
You shouldn't be using a catch-all block. You might end up swallowing other important exceptions
In your particular case, there are other ways to check whether the session has those variables without throwing an exception, such as a simple null check (Session["epdqOrderNo"] == null), so I wouldn't even use try/catch here.
You can assign "" if they are null as follows using ?? as follow
zOrder = Session["epdqOrderNo"]??"";
zOrder = (string) (Session[""] ?? "");
In an ASP.NET MVC app, I have code that boils down to the following:
public ActionResult Test() {
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
}
... do additional validation ...
if (ModelState.IsValid) {
return RedirectToAction("Success?" + query);
}
return View(); // Show validation messages
}
The above code has a compile error ... query might not be initialized.
However, the logic in the code will clearly initialize query before using it.
What is the best way to resolve this issue?
The C# compiler is looking at your code and seeing that the value of the variable is initialized in a try block and is then used later on. It can see that a logical branch of execution exists where an exception is thrown, is caught, and then the subsequent code is executed with an uninitialized value.
The simplest way to stifle the error is to assign a default value to the field. null is sufficient. As you're adding the error to the MVC model state and are checking that value later on before accessing query, you shouldn't be in a situation when the default value will matter.
You are wrong, What if GenerateQueryString throws an exception? What will be the value of Query?
You might want to do a query = "Error"; or something in your catch block. This because appareantly you want the application to run if an exception in GenerateQueryString is thrown.
EDIT
I would recommend against presetting query with a default value. This because the meaning is different. A default value is different than a certain value at a certain moment. Doing so will also prevent the compiler from warning you when you create a new code path but forget to setup a value for query
If there is exception in the call to GenerateQueryString the value of query will be undefined.
Try
string query = string.Empty;
to have a definite assignment to the variable.
Alternatively, if an exception should abort the execution, this will work too:
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
return View();
}
The Code is NOT clearly initialized. When the GenerateQueryString() Method throws an Exception, no value will be set. You should set the String to null and check for null before you use it, als you don't break in the catch-block.
Just because YOU know that it will be initialized (it may not be by the way in your code), the COMPILER can't know that - it's called the Halting problem.
So the compiler errs on the side of caution, something .net does a lot (e.g., no fallthrough in switch..case).
The thing here is that local variables must be initialized before read - they won't be initialized by default and this prevents from bugs programmers often makes. Some time ago I was looking for the answer to this simple situation:
bool a = true, b;
if (a == true) //here everything is OK, because a is initialized
b = true;
if(b == false) //here you get an error, I thought b == false by default
return;
I found on stackoverflow deep explanations, why it works so(couldn't find at the moment which I was reading). But you can read Absence of evidence is not evidence of absence interesting article. Maybe it will explain what I tried to say :)
Resume:
In your case you need to initialize query or set variable in catch block
Just change the declaration of query in: string query = string.Empty;.
The problem is that query is initialised in the try block, but query is declared in the block above. You must initialise it at the top level block.
It could just be that your GenerateQueryString() throws an exception. Personally, I prefer to initialize my variables, just to be on the safe side. For this reason you might just initialize to query to:
string query = String.Empty;
It doesn't hurt to be on the safe side.
I know that you should always check incoming params to a method for null. But what if I have this scenario with a try/catch referring to a local variable. Do I really need to check for null below? Because it's gonna catch it anyway if it's null and the next line of code tries to use the refundResponse variable:
public string DoRefund(...)
{
try
{
......
string refundTransactionID = string.Empty;
......
RefundTransactionResponseType refundResponse = transaction.DoRefund(...);
if (refundResponse != null)
refundTransactionID = refundResponse.RefundTransactionID;
.....
}
catch (Exception ex)
{
LogError(ex);
return ex.ToString();
}
}
Remember I'm talking specifically about local variables and checking those inside a method, not incoming params to a method.
All I'm asking here is do I need to check for null before setting refundTransactionID or do I just set it without the if assuming that the compiler will handle and throw if it is null which will be caught and thrown back as a string to the caller in this case.
or should it be
if (refundResponse == null)
return null;
or just take the check out completely for this local variable assignment and then since in this case I have a try/catch I'm handling any exceptions picked up by the compiler naturally by returning the exception as a string to the caller (it was not my decision to send back a string, it was a requirement by my boss...so bypass that debate for now):
refundTransactionID = refundResponse.RefundTransactionID;
ultimately the rest of the code further down the line in the method is dependent on a valid refundTransactionID.
Exceptions are for exceptional conditions. If you can check for a continuable error, do so, please!
I know that you should always check
incoming params to a method for null.
No, not necessarily. What you should specify is the contract of your method. It's perfectly acceptable (and common) to specify that you'll throw a NullPointer/NullReferenceException for a null parameter. Then you don't need any checking.
You can also check for null, but this only makes sense if you can actually handle a null usefully (e.g. substitute a default value).
You should have to check for null in that instance. Your application logic should be able to handle these kind of situations, without the need for exceptions.
An alternative to testing is the Null Object pattern. Instead of returning Null, or a valid transaction, the transaction::DoRefund() method returns a null object: an object that offers the same interface as the RefundTransactionResponseType instances, but its methods do nothing. With this there is no need to test whether for Null.
The should be used wisely as this can easily hide problems.
No you don't need to check for null, there. That opens up another question, though, do you really need to check for null in incoming parameters?
Remember: that's a behavior. You have to test that behavior.
But if you can't continue at that point let the exception propogate.
No, doesn't look like you should check for null here. And I also wouldn't check for null for ALL incoming parameters (as your description suggests).
It's also odd that you're returning a transactionID as a string OR the message of an exception. How will the caller of this method know if an exception happened?
If you really want to log the exception, how about something like this:
public string DoRefund(...)
{
try
{
return transaction.DoRefund(...).RefundTransactionID;
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
You should check for null rather than letting the exception handling handle it. As leppie said, exceptions are for exceptional conditions not normal flow of control. If you know what issues can occur then you should gracefully handle them.
Another thing to keep in mind is the performance impact of exceptions. When the exception is thrown the JVM has to unwind the call stack. In your example the exception is then also logged. All of this takes time and is much slower than a simple "if" check.
I'd suggest checking for the null then doing some kind of soft error handling instead of just letting it catch and throwing an error message.
It depends on what it means to your program when (refundResponse == null). If this has some meaning, then it makes sense to report a more informative error. If it should never happen and would indicate a flaw in the DoRefund method, then I think it's fine to allow the null to cause an exception later. In the latter case, I'd only have a specific check if you're suspicious of the method and whether it's behaving as it's supposed to.