views:

750

answers:

17

Consider the following method signature:

public static bool TryGetPolls(out List<Poll> polls, out string errorMessage)

This method performs the following:

  • accesses the database to generate a list of Poll objects.
  • returns true if it was success and errorMessage will be an empty string
  • returns false if it was not successful and errorMessage will contain an exception message.

Is this good style?

Update: Lets say i do use the following method signature:

public static List<Poll> GetPolls()

and in that method, it doesn't catch any exceptions (so i depend the caller to catch exceptions). How do i dispose and close all the objects that is in the scope of that method? As soon as an exception is thrown, the code that closes and disposes objects in the method is no longer reachable.

+41  A: 

That method is trying to do three different things:

  1. Retrieve and return a list of polls
  2. Return a boolean value indicating success
  3. Return an error message

That's pretty messy from a design standpoint.

A better approach would be to declare simply:

public static List<Poll> GetPolls()

Then let this method throw an Exception if anything goes wrong.

VoteyDisciple
Having a TryGetPolls could be useful if it can legitimately return nothing.
Michael
+1 for a clean solution
Partha Choudhury
@Michael: the "Try..." methods are nice in specific cases where something can go wrong but you don't care (more-or-less). If it can legitimately return nothing then it should return null/Nothing.
STW
Both VoteyDisciple and yshuditelu's answers are correct. For example, int.Parse also has a int.TryParse for instances where you're expecting the parse to possibly fail. Parse throws an exception, while TryParse returns a bool and uses an out param.
Will Eddins
I don't disagree, but my preference in that case would be a HasPolls() method that simply returns a boolean (or throws an Exception). With some trivial caching, these methods could even be called in succession without loss of performance.
VoteyDisciple
+1 for reducing the amount of work needed to use the method and for making it usable in a linq method chain. And it can return an empty list or null if there's nothing to return.
Oren Trutner
@Yoooder - The pattern in the framework (TryParse, TryGetValue, etc.) is to return a bool, not null.
Michael
note that .NET's (numeric).TryParse() was a late entry and only created because it was found to be a very common case that the parse would fail. It's not considered a framework standard to model off of, and instead more of a specific implementation for a specific (yet common) problem.
SnOrfus
if you can test and return value instead of throwing exceptions left and right I believe that would be better.
Makach
@SnOrfus: Also note that when failure is common, TryParse is faster, since it avoids a throw. Yes, people have benchmarked this. And yes, this often doesn't matter.
Brian
Why do you need to try first? If there are no records then the collection should just be empty.
JC
+1 ... I agree it makes a mess... Besides TryParse or TryGet or TryBlah methods are usually used because you **don't** want to know about any errors. If you're looking for an error message, call the non-Try version of the method and handle the Exceptions!
blesh
I'd make it IEnumerable<Poll> instead of List<Poll>. Otherwise, I agree with this. Throw an exception if something goes wrong, and let the exception contain the error message. The main reason for TryParse is because parsing is something you do all over the place, and the constant exceptions get really annoying, especially if you have break-on-exception turned on in VS.
Kyralessa
(Also, in any case where there could legitimately be no items returned, it's more intuitive and less of a hassle to return an empty list rather than returning null.)
Kyralessa
Compare the code for the version that returns a bool, and the version that throws an exception. You'll find they're about the same level of verbosity.Exceptions in C# are used to indicate that the class could not do what was requested of it, *regardless of whether or not that's considered exceptional*. Since you're probably not calling this method too frequently, you're probably fine for performance. And the "if HasRecords().. GetRecords()" type of solution is subject to all kinds of race conditions.
kyoryu
+11  A: 

I believe

public static bool TryGetPolls(out List<Poll> polls)

would be more appropriate. If the method is a TryGet then my initial assumption would be there is reason to expect it to fail, and onus is on the caller to determine what to do next. If they caller is not handling the error, or wants error information, I would expect them to call a corresponding Get method.

Timothy Carter
Even better, use an IList<Poll> for increased abstraction.
Callum Rogers
+7  A: 

As a general rule, I would say no.

The reason I say no is actually not because you're performing a TryGetX and returning a bool with an out parameter. I think it's bad style because you're also returning an error string.

The Try should only ignore one specific, commonly-encountered error. Other problems may still throw an exception with the appropriate exception message. Remember that the goal of a Try method like this is to avoid the overhead of a thrown exception when you expect a particular, single sort of failure to happen more frequently than not.

Instead, what you're looking for is a pair of methods:

public static bool TryGetPolls( out List<Poll> polls );
public static List<Poll> GetPolls();

This way the user can do what's appropriate and GetPolls can be implemented in terms of TryGetPolls. I'm assuming that your staticness makes sense in context.

Greg D
+7  A: 

Consider returning:

  • an empty collection
  • null

Multiple out parameters, to me, is a code smell. The method should do ONE THING only.

Consider raising and handling error messages with:

throw new Exception("Something bad happened");
//OR
throw new SomethingBadHappenedException();
p.campbell
+1: Also consider implementing a custom exception for the known case where it will fail given certain conditions.
SnOrfus
But you should throw something more specific than a System.Exception which fits the type of error more precisely.
Ian G
Thanks Ian. It was meant more as guideline that an Exception of some kind should be thrown. Wasn't meant to be a literal copy/paste from the Bathroom Wall of Code. :)
p.campbell
+1  A: 

It depends on what the error message is. For instance, if processing couldn't continue because the database connection wasn't available, etc., then you should throw an exception as other people have mentioned.

However, it may be that you just want to return "meta" information about the attempt, in which case you just need a way to return more than one piece of information from a single method call. In that case, I suggest making a PollResponse class that contains two properties: List < Poll > Polls, and string ErrorMessage. Then have your method return a PollResponse object:

class PollResponse
{
    public List<Poll> Polls { get; }
    public string MetaInformation { get; }
}
Scott Whitlock
That's as un-idiomatic as the original code, IMHO. Idiomatic C# uses exceptions to report errors, not custom objects with error messages in them.
Greg Beech
Scott's technique here may be similar to System.Web.HttpResponse I don't think it's an unfair assumption that handling a collection of Poll objects might warrant an entirely new object which handles errors, languages, expiration, user visibility level, etc.
Jim Schubert
@Greg - I think it comes down to what errorMessage really is. Everyone here is just assuming that it's a program exception, but that's not necessarily the case. A program exception means execution couldn't continue. An exception and an error aren't the same thing. When a user tries to enter a character into a number field, that's an error, but I don't have to throw an exception. Maybe in this case the "error" is that the Poll data is stale, or maybe the results don't add up to 100%. I was thinking more along the lines of "how do I return two things from a function call?"
Scott Whitlock
@Jim This isn't exactly an HttpResponse in the question.
Stuart Branham
@Stuart - I'm not bowing to peer pressure. There is nothing wrong with this method under appropriate circumstances. It's perfectly legitimate to return metadata along with a request to "Get" something about what happened during the process.
Scott Whitlock
@Scott - I entirely agree that it's often useful to return additional metadata with a result (we do it all the time, e.g. having an ISearchResult<T> interface which extends IEnumerable<T> and also reports things like the total number of available items in a paged query). I just think in this particular case this isn't what the user is getting at, and they're trying to have an "errors without exceptions model". I didn't down-vote this because I don't think it's either a wrong or unhelpful answer, I just don't think it's the right approach in the presented case.
Greg Beech
@Greg - you are probably correct. I'm going to leave this up because I think that, unlike the rest of the me-too answers, this one adds some extra insight, for anyone willing to scroll to the bottom of the page. We are trying to create a searchable database of question/answers here for future reference, not just answer this one person's question.
Scott Whitlock
@Scott - Have an up-vote... at least it might bump you up off *dead* bottom :-)
Greg Beech
A: 

Depends on if an error is a common occurance or if it us truly an exception.

If errors are gunuinely rare and bad then you might want to consider having the method just return the list of polls and throw an exception if an error occurs.

If an error is something that is realtively common part of normal operations, as like an error coverting a string to an integer in the int.TryParse method, the method you created would be more appropriate.

I'm guessing the former is probably the best case for you.

James Conigliaro
I agree with all of your reasoning except that in the 2nd case, I'd use yshuditelu's advice, not the original code.
Brian
I don't think "rarity" is the right concept. "Exceptional" is more precise. Consider a function accepting a number as a string as an argument. If the string isn't a number, that's an exceptional case, although not necessarily a rare one.
Stuart Branham
+11  A: 

This is definitely not an idiomatic way of writing C#, which would also mean that it probably isn't a good style either.

When you have a TryGetPolls method then it means you want the results if the operation succeeds, and if it doesn't then you don't care why it doesn't succeed.

When you have simply a GetPolls method then it means you always want the results, and if it doesn't succeed then you want to know why in the form of an Exception.

Mixing the two is somewhere in between, which will be unusual for most people. So I would say either don't return the error message, or throw an Exception on failure, but don't use this odd hybrid approach.

So your method signatures should probably be either:

IList<Poll> GetPolls();

or

bool TryGetPolls(out IList<Poll> polls);

(Note that I'm returning an IList<Poll> rather than a List<Poll> in either case too, as it's also good practice to program to an abstraction rather than an implementation.)

Greg Beech
Greg, this is an excellent point.
Jim Schubert
+1 for IList - I should have mentioned that too.
Scott Whitlock
I am all for abstraction in a public API specially if the client is not in your control. But if this is an internal class how likely is that you would replace the List implementation in .Net framework with something else. If it was an interface that you can mock fair enough, but .Net List class ? How about KISS principle.
Pratik
@Pratik - How is an IList<T> any more complex than a List<T>? It's just an extra "I" on the front. And it makes your library more robust in the face of change. How often? I don't know. We've done it several times on the current project. And each time, the calling code didn't have to change.
Greg Beech
@Greg - It is not complex at all for the declaring class. But for internal classes where you code the user of the class as well you often have to create a list again, use AddRange and then only you can use the List ForEach method. Returning a List directly simplifies this. I am curious to know what collection class you used to replace List<T>, several times, assuming that is what you used as the concrete implementation of IList<T>.
Pratik
Why would you use the List<T>.ForEach method? It serves no purpose. You already have a foreach loop, or could write an extension ForEach method trivially. As for what we replaced it with - other collections with different performance characteristics, e.g. a KeyedCollection when it became clear the exposing class often needed to access the collection as a dictionary, whereas users of the class need to access it as a list. Exposing it as IList<T> allowed us to do this without breaking any of the consumers.
Greg Beech
+2  A: 

No, from my point of view this is very bad style. I would write it like this:

public static List<Poll> GetPolls();

If the call fails, throw an exception and put the error message in the exception. That's what exceptions are for and your code will become much cleaner, more readable and easier to maintain.

Achim
A: 

It depends on how frequently the method will fail. In general, errors in .Net should be communicated with an Exception. The case where that rule doesn't hold is when the error condidition is frequent, and the performance impact of throwing and exception is too high.

For Database type work I think an Exception is best.

Scott Weinstein
A: 

I'd restate it like this.

public static List<Poll> GetPolls()
{
    ...
}

It should probably be throwing an exception (the errorMessage) if it fails to retrieve the polls, plus this allows for method chaining which is less cumbersome than dealing with out parameters.

If you run FxCop, you'll want to change List to IList to keep it happy.

48klocs
+1  A: 

Not really - I can see a number of problems with this.

First of all, the method sounds like you'd normally expect it to succeed; errors (cannot connect to database, cannot access the polls table etc) would be rare. In this case, it is much more reasonable to use exceptions to report errors. The Try... pattern is for cases where you often expect the call to "fail" - e.g. when parsing a string to an integer, chances are good that the string is user input that may be invalid, so you need to have a fast way to handle this - hence TryParse. This isn't the case here.

Second, you report errors as a bool value indicating presence or absence of error, and a string message. How would the caller distinguish between various errors then? He certainly can't match on error message text - that is an implementation detail that is subject to change, and can be localized. And there might be a world of difference between something like "Cannot connect to database" (maybe just open the database connection settings dialog in this case and let the user edit it?) and "Connected to database, but it says 'Access Denied'". Your API gives no good way to distinguish between those.

To sum it up: use exceptions rather than bool + out string to report messages. Once you do it, you can just use List<Poll> as a return value, with no need for out argument. And, of course, rename the method to GetPolls, since Try... is reserved for bool+out pattern.

Pavel Minaev
A: 

I think its fine. I would prefer though:

enum FailureReasons {}
public static IEnumerable<Poll> TryGetPolls(out FailureReasons reason)

So the error strings don't live in the data-access code...

Frank Schwieterman
A: 

C# Methods should really only do one thing. You're trying to do three things with that method. I would do as others have suggested and throw an exception if there is an error. Another option would be to create extension methods for your List object.

e.g. in a public static class:

public static List<Poll> Fill( this List<Poll> polls) {
   // code to retrieve polls
}

Then, to call this, you would do something like:

List<Poll> polls = new List<Poll>().Fill();
if(polls != null)
{
  // no errors occur
}

edit: i just made this up. you may or may not need the new operator in List<Poll>().Fill()

Jim Schubert
A: 

Please state your assumptions, constraints, desires/goals, and reasoning; we're having to guess and/or read your mind to know what your intentions are.

assuming that you want your function to

  • create the polls list object
  • suppress all exceptions
  • indicate success with a boolean
  • and provide an optional error message on failure

then the above signature is fine (though swallowing all possible exceptions is not a good practice).

As a general coding style, it has some potential problems, as others have mentioned.

Steven A. Lowe
A: 

The guidelines say to try to avoid ref and out parameters if they are not absolutely required, because they make the API harder to use (no more chaining of methods, the developer has to declare all the variables before calling the method)

Also returning error codes or messages is not a best practice, the best practice is to use exceptions and exception handling for error reporting, else errors become to easy to ignore and there's more work passing the error info around, while at the same time losing valuable information like stacktrace or inner exceptions.

A better way to declare the method is like this.

public static List<Poll> GetPolls() ...

and for error reporting use exception handling

try 
{
   var pols = GetPols();
   ...
} catch (DbException ex) {
   ... // handle exception providing info to the user or logging it.
}
Pop Catalin
A: 

There is also this pattern, as seen in many Win32 functions.

public static bool GetPolls(out List<Poll> polls)


if(!PollStuff.GetPolls(out myPolls))
  string errorMessage = PollStuff.GetLastError();

But IMO it's horrible. I would go for something exception based unless this method has to run 65times per second in a 3d game physics engine or someting.

A: 

Did I miss something here? The question asker seems to want to know how to clean up resources if the method fails.

public static IList<Poll> GetPolls()
{
    try
    {
    }
    finally
    {
        // check that the connection happened before exception was thrown
        // dispose if necessary
        // the exception will still be presented to the caller
        // and the program has been set back into a stable state
    }
}

On a design side note, I'd consider pushing this method into a repository class so you have some sort of context with which to understand the method. The entire application, presumably, is not responsible for storing and getting Polls: that should be the responsibility of a data store.

Sam Pearson