Static code analysis on mandatory variable evaluation - c#

I have this C# solution in which we use a certain pattern. A function returns true/false whether it succeed, and some value. If the function returned false, the value may not be used. Thus in the scope where such a function (with this particular pattern) is called, the IsSuccessful boolean must be evaluated.
We work with VS2013 + ReSharper 9. Is there a way to automatically check whether this pattern is obeyed in the code? If it is not possible with these tools, are there other tools? My last resort would be to write a unit test that performs this static code analysis.
Code example:
public ReturnValue<T> MyMethod()
{
try
{
....
return new ReturnValue<T>(someValue);
}
catch(Exception ex)
{
return new ReturnValue<T>(ex);
}
}
var returnValue = MyMethod();
if(!returnValue.IsSuccesful)
{
//Log error
return; //Can't go on, previous function failed
}
//Is successful continue code
public class ReturnValue<T>
{
public bool IsSuccessful { get; private set; }
public T Value { get; private set; }
public ReturnValue<T>(Exception ex)
{
IsSuccessful = false;
}
public ReturnValue<T>(T valueToReturn)
{
IsSuccessful = true;
Value = valueToReturn;
}
}
Edit:
I semi-solved my issue. Upon creation of the object the current stacktrace is saved (new StackTrace()). Upon destruction of the object (when the garbage collectors cleans it up), it is checked whether the IsSuccesful property of the object was ever evaluated during its lifespan. If not, a warning with the stacktrace is logged.

Related

Using IsValueCreated before accessing LazyLoadObject.Value

I'm working with some C# code that's using .Net 4 Lazy loads and I'm not super familiar with it. I'm trying to figure out if this particular code is useless or not.
Originally the property and code below where in the same class, but now I've moved the code to an external class that no longer has access to the private "lazyRecords" property. I'm wondering what the point of checking "lazyRecords.IsValueCreated" is since the lazyRecords.Value has not been invoked yet, wouldn't it always be false? Or is it checking to see if another thread somehow invoked the Value? Or is it doing this in case of a thread exception that resulted in not loading the object?
Property:
private Lazy<List<Record>> lazyRecords;
public List<Record> Records
{
get
{
return lazyRecords.Value;
}
set
{
lazyRecords = new Lazy<List<Record>>(() => value);
}
}
Code:
public Category LoadCategory(BaseClient client)
{
Category category = new Category();
category.Records = client.RecordClient.GetRecordsByCategoryID(category.ID);
if (lazyRecords.IsValueCreated)
{
category.WorldRecord = category.Records.FirstOrDefault();
}
else
{
category.WorldRecord = client.RecordClient.GetWorldRecord(category.ID);
}
}
The code is pretty useless, yes. To help you understand why, consider this very minimal version of Lazy (the real class has more options and logic to take care of multiple threads, but this is the rough idea):
public class Lazy<T>
{
private readonly Func<T> _creator;
private T _cachedValue;
public Lazy(Func<T> creator) => _creator = creator;
public bool IsValueCreated { get; private set; }
public T Value
{
get
{
if (!IsValueCreated)
{
_cachedValue = _creator();
IsValueCreated = true;
}
return _cachedValue;
}
}
}
The delegate passed to the constructor is called on demand, the first time the Value is requested. In the code you've posted there is no point to this because the delegate simply returns the value passed into the setter.
As to the LoadCategory method, the code you posted is hard to decipher. It directly accesses lazyRecords, implying it's a method of the same class. But then it accesses Records on a different object.

Is there an alternative to the Notification pattern for multiple messages and success/failure?

Is there an alternative to the Notification pattern for multiple messages and success/failure?
I have a class, OperationResult, that I use to return a Success boolean and a list of "error" messages. These messages are sometimes unexpected errors but more often ordinary cases that often happen. Sometimes we return single error messages but other times we return several. I'm hoping to find a better way.
This seems to be more or less the Notification pattern advocated by Fowler. The consumers then do something reasonable with the success state and the errors, most often displaying errors to the user but sometimes continuing on in the case of non-fatal errors.
I thus have lots of service methods (not web service methods) that look something like this:
private ThingRepository _repository;
public OperationResult Update(MyThing thing)
{
var result = new OperationResult() { Success = true };
if (thing.Id == null) {
result.AddError("Could not find ID of the thing update.");
return result;
}
OtherThing original = _repository.GetOtherThing(thing.Id);
if (original == null) return result;
if (AnyPropertyDiffers(thing, original))
{
result.Merge(UpdateThing(thing, original));
}
if (result.Success) result.Merge(UpdateThingChildren(thing));
if (!result.HasChanges) return result;
OperationResult recalcResult = _repository.Recalculate(thing);
if (recalcResult.Success) return result;
result.AddErrors(recalcResult.Errors);
return result;
}
private OperationResult UpdateThing(MyThing ) {...}
private OperationResult UpdateThingChildren(MyThing) {...}
private bool AnyPropertyDiffers(MyThing, OtherThing) {...}
As you can imagine, UpdateThing, UpdateThingChildren, and ThingRepository.Recalculate all have similar OperationResult merging/manipulating code interleaved with their business logic.
Is there an alternative to so much code munging around my returned object? I'd like my code to just focus on the business logic without having to be so particular about manipulating an OperationResult.
I'm hoping to instead have code that looks something like the following, something that better expresses its business logic with less message-handling cruft:
public ??? Update(MyThing thing, ???)
{
if (thing.Id == null) return ???;
OtherThing original = _repository.GetOtherThing(thing.originalId);
if (original == null) return ???;
if (AnyPropertyDiffers(thing, original))
{
UpdateThing(thing, original));
}
UpdateThingChildren(thing);
_repository.Recalculate(thing);
return ???;
}
Any ideas?
Note: throwing exceptions isn't really appropriate here as the messages aren't exceptional.
I think this a situation where functional programming can help, so I'd try with a package porting some F# feautures to C#
using Optional;
and since we want to manage exceptions
using Optional.Unsafe;
At this point we can introduce a helper, to do the typical functional "monad chaining"
public static class Wrap<Tin, Tout>
{
public static Option<Tout, Exception> Chain(Tin input, Func<Tin, Tout> f)
{
try
{
return Option.Some<Tout,Exception>(f(input));
}
catch (Exception exc)
{
return Option.None<Tout, Exception>(exc);
}
}
public static Option<Tout, Exception> TryChain(Option<Tin, Exception> input, Func<Tin, Tout> f)
{
return input.Match(
some: value => Chain(value, f),
none: exc => Option.None<Tout, Exception>(exc)
);
}
}
Now, assuming we have the following updates, that can throw exceptions:
Type2 Update1 (Type1 t)
{
var r = new Type2();
// can throw exceptions
return r;
}
Type3 Update2(Type2 t)
{
var r = new Type3();
// can throw exceptions
return r;
}
Type4 Update3(Type3 t)
{
var r = new Type4();
// can throw exceptions
return r;
}
we'll be able to write a logical flow just following the Happy Path
Option<Type4, Exception> HappyPath(Option<Type1, Exception> t1)
{
var t2 = Wrap<Type1,Type2>.TryChain(t1, Update1);
var t3 = Wrap<Type2, Type3>.TryChain(t2, Update2);
return Wrap<Type3, Type4>.TryChain(t3, Update3);
}
Finally, with an extension class like
public static class Extensions {
public static Option<Type2, Exception> TryChain(this Option<Type1, Exception> input, Func<Type1, Type2> f)
{
return Wrap<Type1, Type2>.TryChain(input, f);
}
public static Option<Type3, Exception> TryChain(this Option<Type2, Exception> input, Func<Type2, Type3> f)
{
return Wrap<Type2, Type3>.TryChain(input, f);
}
public static Option<Type4, Exception> TryChain(this Option<Type3, Exception> input, Func<Type3, Type4> f)
{
return Wrap<Type3, Type4>.TryChain(input, f);
}
}
the Happy Path can be written in a beautiful form
Option<Type4, Exception> HappyPath(Option<Type1, Exception> t1)
{
var t2 = t1.TryChain(Update1);
var t3 = t2.TryChain(Update2);
return t3.TryChain(Update3);
}
I would argue that your service is not doing one thing. Its responsible for validating input and then if validation succeeds updating things. And yes I agree that user needs as many information about errors (violations, name not provided, description to long, date end before date start etc) as you can produce on single request and with that the exceptions are not the way to go.
In my projects I tend to separate concerns of validation and update so the service that does the update has little to none chance of failure. Also I like the strategy pattern to do both validation and update - user requests a change the generic service accepts request of validation/update, calls specific validator/updater which in turn calls generic service to validate/update some dependencies. The generic service will merge results and decide upon success or failure of the operation. The obvious benefit is that violation messages merging is done once in some generic class and specific validator/updater can focus on single entity. On the other hand you might want to validate some database uniqueness or existence of objects on the database this exposes two concerns: extra queries to database (light queries that use Exist to minimize output but its a trip to the database) and the latency between validation and update (in that time database can change and your uniqueness or existence verification can change (this time is relatively small but it can happen). This pattern also minimizes duplication of UpdateThingChildren - when you have simple many to many relation the child can be updated from either one of connected entities.
First, to shortly answer your question, there is no alternative to Notification pattern for combining multiple responses into one. Even if you could throw an exception, you'd have AggregateException which is nothing other than Notification pattern for collecting several exceptions into one (exception is just one kind of output that the method can have).
Notification pattern is a great pattern and I don't see a reason to avoid it actually. Yes, your service layer methods look somewhat chatty, indeed, but those could be refactored. While you have not really asked for the advice how this could be refactored, you need to think about that part mostly.
Couple of advises by looking at your code and in general:
It's normal to make Notification pattern a primary pattern in your codebase if applicable. Not just in the service layer, but everywhere else too. If a method returns more than a primitive value as a result, I don't see how else you would do it. So, every method could return OperationResult{TResult} (generic), which indicates the success/failure, as well as the result of the operation - list of errors if failure, TResult object if success. Every caller method will decide what to do with the result - either discard part or all of it, or return it to its caller up in the call stack.
In your code, you have UpdateThingChildren private method. I'm not sure what that does, but it would be much better expressing the intention if you do thing.UpdateChildren() call on the thing itself.
To decrease the chattiness of your service method, you could use fluent interface-like method chaining. It should not be difficult to implement, assuming that every operation you call returns OperationResult. I'd expect your code to look like this at a minimum:
private ThingRepository _repository;
public OperationResult Update(MyThing thing)
{
return new OperationResult() //removed Success = true, just make that a default value.
.Then(() => thing.ValidateId()) //moved id validation into thing
.Then(() => GetOtherThing(thing.Id)) //GetOtherThing validates original is null or not
.Then(() => thing.AnyPropertyDiffersFrom(original)) //moved AnyPropertyDiffers into thing
.Then(() => thing.UpdateChildren())
.Then(() => _repository.Recalculate(thing));
}
private OperationResult GetOtherThing(MyThing ) {...}
As you can imagine, implementing Then method is not difficult at all. It's defined on OperationResult and takes Func{OperationResult} (generic) as argument. It does not execute func if success == false. Otherwise, it executes func and merges the operation result with itself. At the end, it always returns itself (this).
Some people understand that patterns are not to be broken. But patterns have many critics. And there is really room for improvisation. You still can consider that you have implemented a pattern even if you modified some details. Pattern is general thing and can have specific implementation.
Saying that, you can choose not to go with such fine-grained operation result parsing. I always advocated for something like this pseudo-code
class OperationResult<T>
{
List<T> ResultData {get; set;}
string Error {get; set;}
bool Success {get; set;}
}
class Consumer<T>
{
void Load(id)
{
OperationResult<T> res = _repository.GetSomeData<T>(id);
if (!res.Success)
{
MessageBox.Show(DecorateMsg(res.Error));
return;
}
}
}
As you see, server code return data or error message. Simple. Server code does all the logging, you can write errors to DB, whatever. But I see no value passing complex operation results to consumer. Consumer only needs to know, success or not. Also, if you get multiple things in same operation, what the sense to continue operation if you fail get first thing? May be the problem that you trying to do too many things at once? It is arguable. You can do this
class OperationResult
{
List<type1> ResultData1 {get; set;}
List<type2> ResultData2 {get; set;}
List<type3> ResultData3 {get; set;}
string[] Error {get; set;} // string[3]
bool Success {get; set;}
}
In this case you may fill 2 grids but not third one. And if any errors occur on client side because of this, you will need to handle it with client error handling.
You definitely should feel free to adjust any patterns for your specific needs.
I see two possible options that you could use while avoiding throwing exceptions, but in the end we are only reducing the amount of code needed for messages:
I would refactor the code a little bit in order to make it more standard across all calls. Like the following (See comments inside the parenthesis in the code comments):
public OperationResult Update2(MyThing thing)
{
var original = _repository.GetOtherThing(thing.Id);
if (original == null)
{
return OperationResult.FromError("Invalid or ID not found of the thing update.");
}
var result = new OperationResult() { Success = true };
if (AnyPropertyDiffers(thing, original))
{
result.Merge(UpdateThing(thing, original));
if (!result.HasChanges) return result;
}
result.Merge(UpdateThingChildren(thing));
if (!result.HasChanges) return result;
result.Merge(_repository.Recalculate(thing));
return result;
}
_repository.GetOtherThing - Delegate Id checking to the repository, for simpler code and to ensure we return an error if nothing happened
UpdateThing - With exit after no changes
_repository.Recalculate - We now merge results and return them
Use a scope class shared by all the services at the construction of the services.
// We a scope class shared by all services,
// we don't need to create a result or decide what result to use.
// It is more whether it worked or didn't
public void UpdateWithScope(MyThing thing)
{
var original = _repository.GetOtherThing(thing.Id);
if (_workScope.HasErrors) return;
if (original == null)
{
_workScope.AddError("Invalid or ID not found of the thing update.");
return;
}
if (AnyPropertyDiffers(thing, original))
{
UpdateThing(thing, original);
if (_workScope.HasErrors) return;
}
UpdateThingChildren(thing);
if (_workScope.HasErrors) return;
_repository.Recalculate(thing);
}
_repository.GetOtherThing must add any errors to the _workScope
UpdateThing must add any errors to the _workScope
UpdateThingChildren must add any errors to the _workScope
_repository.Recalculate must add any errors to the _workScope
In this last example we don't need to return anything since the caller will have to verify if the scope is still valid.
Now if there are multiple validations to be performed I would suggest doing another class like Rafal mentioned.
Last note: I would throw exceptions for anything that should be handled in the GUI like the 'thing.Id' sent without a value or not sent at all, that sounds to me like whoever did the interface didn't handle this scenario properly or the current interface is old or unsupported, which normally is enough reason to throw an exception.
You can use exceptions internally without throwing them to callers. This allows you to break out of a failed operation easily, and groups your business logic all in one place. There is still some 'cruft', but it's separated (and could be in its own class) from the business logic, which is contained in the *Internal implementations. Not saying this is the best or only way of approaching this problem, but I may go with this:
public class OperationResult
{
public bool Success { get; set; }
public List<string> Errors { get; set; } = new List<string>();
}
public class Thing { public string Id { get; set; } }
public class OperationException : Exception
{
public OperationException(string error = null)
{
if (error != null)
Errors.Add(error);
}
public List<string> Errors { get; set; } = new List<string>();
}
public class Operation
{
public OperationResult Update(Thing thing)
{
var result = new OperationResult { Success = true };
try
{
UpdateInternal(thing);
}
catch(OperationException e)
{
result.Success = false;
result.Errors = e.Errors;
}
return result;
}
private void UpdateInternal(Thing thing)
{
if (thing.Id == null)
throw new OperationException("Could not find ID of the thing update.");
var original = _repository.GetOtherThing(thing.Id);
if (original == null)
return;
if (AnyPropertyDiffers(thing, original))
result.Merge(UpdateThing(thing, original));
result.Merge(UpdateThingChildren(thing));
if (result.HasChanges)
_repository.Recalculate(thing);
}
}
I would approach with State pattern and internal collection to save information. You can start applying events that change the state and store the information related to the applied event. Finally call get information to wrap them inside operationresult.
A pseudo code
public OperationResult Update(MyThing thing)
{
return new OperationResult
{
Errors = thing.ApplyEvent(Event.NullCheck)
.ApplyEvent(Event.OriginalNullCheck)
.ApplyEvent(Event.OriginalPropertyDiffersCheck)
.CollectInfo(),
Success = true
};
}
public class MyThing
{
private List<string> _errors = new List<string>();
private MyThing _original;
public MyThingState ThingState {get;set;}
public MyThing ApplyEvent(Event eventInfo)
{
MyThingState.ApplyEvent(this, eventInfo)
}
}
public class NullState : MyThingState
{
public MyThing ApplyEvent(MyThing myThing, Event eventInfo)
{
if(mything == null)
{
// use null object pattern
mything.AddErrors("Null value")
// Based on the event, you select which state to instantiate
// and inject dependencies
mything.State = new OriginalNullState();
}
}
}
public class OriginalNullState : MyThingState
{
public void ApplyEvent(MyThing myThing, Event eventInfo)
{
// Get original from database or repository
// Save and validate null
// Store relevant information in _errors;
// Change state
}
}
Even though I would have loved throwing exception, here it is not appropriate because you are not in fail-fast. You are taking corrective measures on non fatal cases. You just want higher layers to know about it.
public OperationResult<DataSet> Update(MyThing thing, OperationResult<DataSet> papa)
{
// Either you have a result object from enclosing block or you have null.
var result = OperationResult<DataSet>.Create(papa);
if (thing.Id == null) return result.Fail("id is null");
OtherThing original = _repository.GetOtherThing(thing.originalId);
if (original == null) return result.warn("Item already deleted");
if (AnyPropertyDiffers(thing, original))
{
UpdateThing(thing, original, result));
// Inside UpdateThing, take result in papa and do this dance once:
// var result = OperationResult<DataSet>.Create(papa);
}
UpdateThingChildren(thing, result);
// same dance. This adds one line per method of overhead. Eliminates Merge thingy
_repository.Recalculate(thing, result);
return result.ok();
}
You can eliminate passing result everywhere using Scope pattern from #BigShot, but i personally do not like ambient contexts. The could be anything you may need to return back.
class OperationResult<T> {
enum SuccessLevel { OK, WARN, FAIL }
private SuccessLevel _level = SuccessLevel.OK;
private List<String> _msgs = new ...
public T value {get; set};
public static OperationResult<T> Create(OperationResult<T> papa) {
return papa==null ? new OperationResult<T>() : papa;
}
public OperationResult<T> Fail(string msg) {
_level = SuccessLevel.Fail;
_msgs.add(msg);
return this; // this return self trick will help in reducing many extra lines in main code.
}
// similarly do for Ok() and Warn()
}

Get permitted triggers with guard conditions in Stateless (.NET state machine library)

Background:
I have same Trigger with mutually exclusive guard conditions defined with PermitIf that will cause transition to different states depending on those conditions.
Guards have Descriptions defined and they show up nicely in brackets in exported DOT graph, so it is easy to follow through.
machine
.Configure(Status.Registered)
.PermitIf(Activity.Submit, Status.Submitted, IsGoodRating, "Is good rating")
.PermitIf(Activity.Submit, Status.Denied, IsBadRating, "Is bad rating")
Now, I know there is machine.PermittedTriggers property that returns allowed Triggers in current state which is great, but here is the question.
Question :
Is there a way to get a list of PermittedTriggers with corresponding guard conditions for status Registered in this case?
I guess you could do something like this, but... I don't know how helpful it is:
class Program
{
enum Status { Registered, Submitted, Denied }
static void Main(string[] args)
{
int currentRating = 91;
RatingTrigger RatingTrigger = new RatingTrigger();
StateMachine<Status, Trigger> _sm = new StateMachine<Status, Trigger>(Status.Registered);
_sm.Configure(Status.Registered)
.PermitIf(RatingTrigger, Status.Submitted, () => RatingTrigger.Guard(currentRating), RatingTrigger.GuardDescription)
.PermitIf(RatingTrigger, Status.Denied, () => RatingTrigger.Guard(currentRating), RatingTrigger.GuardDescription);
var list = _sm.PermittedTriggers;
foreach (var item in list)
{
if (item.GetType().Equals(typeof(RatingTrigger)))
{
Console.WriteLine(((RatingTrigger)item).GuardDescription);
}
else
Console.WriteLine(item);
}
}
private static bool evaluate()
{
return true;
}
}
public abstract class Trigger
{
public abstract bool Guard(object something);
}
public class RatingTrigger : Trigger
{
public string GuardDescription = "This Guard evaluaties the current rating. Retuns true if good rating, false if bad rating";
public override bool Guard(object rating)
{
return (((int)rating) > 90);
}
}

Visual Studio debugger automatic variable assignment

Yes, I see the other topic: Visual Studio Debugger - Automatic Variable Assignment
But I needed a solution today, and found one before I see it, and I'm wondering if is there a better one out there?
My case:
I have a list of entities and I set up some policy related property based on a lot of factor. But it's not implemented yet or simply I want to test the UI when the entity has a right and when not (change it as fast as possible to do the real job).
So I set up the entity as if it has the right, so I can test the UI with this. But I don't want to break at every element in the list, and change the flag from true to false (to test the other case). I looked for a way to change a variable from debugger automatically. I came up with this solution:
Set a breakpoint
Setup a condition for it, which is a 'fake' one, but it gonna change the variable's value
run in debug mode
if I need the case 1. I enable the breakpoint, if I need the other one, I disable the breakpoint
Simplified example:
namespace AutoVariable
{
class Program
{
static void Main(string[] args)
{
try
{
new Program().Entrance();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
}
public void Entrance()
{
var entities = new List<Entity>
{
new Entity() { Name = "A" },
new Entity() { Name = "B" },
new Entity() { Name = "C" }
};
entities.ForEach(setRight);
entities.ForEach(Console.WriteLine);
}
protected void setRight(Entity entity)
{
//not implemented
bool hasRight = true;
entity.HasRight = hasRight;
}
}
class Entity
{
public bool HasRight { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("{0} - {1}", Name, HasRight);
}
}
}
I set up a condition breakpoint to: entity.HasRight = hasRight;
with this condition: (hasRight = false)
so the hasRight will be false and the breakpoint never got a hit.
But it can be used in other cases also, for example in Jason Irwin's post, you can use something like: (userName = "Jason").Length < 1
So my question that is it a good solution or I am missing something from the 'native' debugger toolset?
Thanks in advance!
negra
You want to do an action using the debugger right? There's a thing called Trace Points.
It is explained here:
http://weblogs.asp.net/scottgu/archive/2010/08/18/debugging-tips-with-visual-studio-2010.aspx
and go down to "TracePoints – Custom Actions When Hitting a BreakPoint"
Is that what you need?

Using a returned error message to determine if error is present

I was recently talking with a buddy about return values taking only a single meaning. At my previous job, we worked with C++ and had typedef'ed wBOOL so that a 0 was wFALSE, and 1 was wTRUE. The architect said that we can also return 2, 3, 4... for more information, which I think is a horrible idea. If we expect wTRUE = 1 and wFALSE = 0 and wBOOL = {wTRUE, wFALSE}, returning anything else should be avoided... now, on to today's C#.
I recently reviewed a piece of code where there were a collection of functions that determined if there was an error and returned the string back to the user:
private bool IsTestReady(out string errorMessage)
{
bool isReady = true;
errorMessage = string.Empty;
if(FailureCondition1)
{
isReady = false;
errorMessage = FailureMessage1;
}
else if(FailureCondition2)
{
isReady = false;
errorMessage = FailureMessage2;
}
//... other conditions
return isReady;
}
Then, to use these functions...
private enum Tests
{ TestA, TestB, TestC }
private void UpdateUI()
{
string error = string.Empty;
bool isTestReady;
switch(this.runningTest) // which test are we running (TestA, TestB, or TestC)
{
case Tests.TestA:
isTestReady = IsTestAReady(error);
break;
case Tests.TestB:
isTestReady = IsTestBReady(error);
break;
case Tests.TestC:
isTestReady = IsTestCReady(error);
break;
}
runTestButton.Enabled = isTestReady;
runTestLabel.Text = error;
}
I thought to separate these out into two methods:
private string GetTestAErrorMessage()
{
//same as IsTestReady, but only returns the error string, no boolean stuffs
}
private bool IsTestAReady
{
get{ return string.IsNullOrEmpty(GetTestAErrorMessage()); }
}
Does this violate the principal of not having a return value mean more than one thing? For instance, in this case, if there error message IsNullOrEmpty, then there is no error. I think that this does not violate that principal; my co-worked does. To me, it's no different than this:
class Person
{
public int Height {get;}
public bool IsTall() { return Height > 10; }
}
Any thoughts or suggestions on a different approach to this issue? I think the out parameter is the worst of the solutions.
The return value and the error message are technically not bound together. You could have a developer come along at a later time and add a new failure condition to IsTestReady, and that failure condition may not set an error message. Or, perhaps there is a message, but it doesn't exactly represent a failure (like, perhaps a warning or something), so the error message parameter may get set, but the return value is true.
An exception doesn't really work in this case either, for the exact reason that StriplingWarrior wrote in his comment - exceptions should be used for non-normal operational states, and a non-ready test is a normal state.
One solution might be to remove the error message parameter and have the IsTestReady function return a class:
public class TestReadyResult {
public bool IsReady { get; set; }
public string Error { get; set; }
}
There is just one property to check - TestReadyResult.IsReady - for test state, and if necessary, the Error property can be used for non-ready states. There is no extra parameter to manage for the function call, either.
I'm not a big fan of having the null or empty return value indicate that nothing is wrong. A better comparison than the one you gave is:
class Person
{
public int Height {get;}
public bool IsBorn() { return Height > 0; }
}
In .NET, it is common practice to use the "bool return with out parameter" pattern you see in your original method (see the various TryParse methods, for example). However, if you prefer, another solution would be to create a TestReadyCheck class with both the boolean and the string as properties. I've done something similar with the following class, and been quite happy with it.
public class RequestFilterResult
{
public static readonly RequestFilterResult Allow = new RequestFilterResult(true, null);
public static RequestFilterResult Deny(string reason) { return new RequestFilterResult(false, reason); }
protected RequestFilterResult(bool allowRequest, string denialReason)
{
AllowRequest = allowRequest;
DenialReason = denialReason;
}
public bool AllowRequest { get; private set; }
public string DenialReason { get; private set; }
}
This allows for the following usage:
public RequestFilterResult Filter(...)
{
if (FailureCondition1) return RequestFilterResult.Deny(FailureMessage1);
if (FailureCondition2) return RequestFilterResult.Deny(FailureMessage2);
return RequestFilterResult.Allow();
}
It's concise, while enforcing that failure results provide a failure message, and success results don't.
On a side note, the structure of your switch statement feels like a code smell to me. You may want to consider ways to leverage polymorphism. Maybe make each test have its own class, with an IsTestReady method on it?
I would use exceptions to convey information about failure states, rather than relying on the caller to know how to use an error message field (even though it's private).

Categories