Function Result

See the source code on github.

Use on you project via nuget.

Function Result is a pattern for returning more information from the results of a method call.  With the Function Result pattern and library, you can trap errors and other warnings within your method and then return them back to callers in a standard way.  The signature for a method has 3 parts: the name, the parameters if any, and the result.  When using the Function Result pattern, instead of returning your result directly, you wrap the result in the FunctionResult class from the library.  The FunctionResult class looks like this:

public interface IFunctionResult<T>
    {
        FunctionResultExtraData ExtraData { get; }
        FunctionResultMessageList Messages { get; set; }
        FunctionResultOperationStatus OperationStatus { get; set; }
        T ReturnValue { get; set; }
        bool WasSuccessful { get; }
    }

By wrapping your result you can return additional information and messages to callers in a standard way.  The FunctionResult class is implemented with generics so that you can return your real type easily.  In addition to your return value, you also return an operation status, a list of simple messages that can be used to indicate errors, warnings, or validation failures, and a simple extra data dictionary that you can use to return additional values as well.  The Function Result pattern works best for calls between application boundaries like UI and Business layers.

Basic Example

Callee Code
public class MyService
{
     public IFunctionResult<int> DivideTwoNumbers(int x, int y)
     {
         var ret = new FunctionResult<int>();

         try
         {
             if (x == 0)
             {
                 ret.Messages.AddValidation("X can not be 0", "X");
                 ret.OperationStatus = FunctionResultOperationStatus.Error;
                 return ret;
             }

             if (y == 0)
             {
                 ret.Messages.AddValidation("Y can not be 0", "Y");
                 ret.OperationStatus = FunctionResultOperationStatus.Error;
                 return ret;
             }

             ret.ReturnValue = x / y;
             ret.OperationStatus = FunctionResultOperationStatus.Success;
         }
         catch (Exception ex)
         {
             ret.Messages.AddError(ex, false);
             ret.Messages.AddError("Unexpected error dividing two numbers");
             ret.OperationStatus = FunctionResultOperationStatus.Error;
         }

         return ret;
     }
}

Caller Code
var srv = new MyService();

var divNums = srv.DivideTwoNumbers(5, 5);

if (!divNums.WasSuccessful)
{
       //handle errors by displaying the messages 
       //that were added to the result using the Messages property
       divNums.Messages.ForEach(m => Console.Write(m.Message));
}
else
{
       //do something with value
       Console.Write(divNums.ReturnValue);
}

In the above example, the DivideTwoNumbers method from MyService returns an IFunctionResult instance.  By wrapping the method code in a try/catch and returning a FunctionResult you don’t have to worry about catching exceptions, instead you just check the operation status and deal with any messages.  If the operation fails, the messages may be an uncaught error or validation but since they are returned using a FunctionResult, the caller can handle them all in the same way.  This works much better when dealing with code that may cross boundaries using message queues or web service http calls.  FunctionResults are serializable as long as the type you are using is too.

API Documentation

The FunctionResult class has a very simple interface with just a few properties.

Properties
FunctionResultExtraData ExtraData

This is a simple data dictionary that can be used to return additional information to a caller.  Values are stored as objects and retrieved via their string key names.  The FunctionResultExtraData class also provides some helper functions to convert to/from Int, String, Date, and Bool values.

FunctionResultMessageList Messages

The messages collection contains any messages set in the callee code.  Messages have the following types:

Undefined = 1, Error = 2, Warning = 3, Validation = 4, Info = 5, Success = 6

FunctionResultOperationStatus OperationStatus

The operation status indicates whether or not the function was successful.  Here are the possible outcomes:

Error = 0, Success = 1

T ReturnValue

The return value is implemented as a generic.  When you create an instance of the FunctionResult class you specify the type for the return value as the first generic parameter.

bool WasSuccessful

This should be checked by the caller code to determine if the operation was successful.

Leave a Reply

Your email address will not be published. Required fields are marked *