-
Notifications
You must be signed in to change notification settings - Fork 15
Handling Exceptional Events
You can record events in the Log by using
BH.Engine.Reflection.Compute.RecordError(string message)
BH.Engine.Reflection.Compute.RecordWarning(string message)
BH.Engine.Reflection.Compute.RecordNote(string message)
You can access all event logged since the UI was started by calling BH.Engine.Reflection.Query.AllEvents()
Things don't always run according to plan. Two typical situations can occur:
- The input value your method received are invalid or insufficient to generate the output.
- The methods you call inside your method are failing
In either case, you are generally left with a few choices:
- throw an exception,
- return a null value,
- return a dummy value.
The first option stops the execution of the code completely while the other two allows things to continue but with the risk of the problem remaining unnoticed. A lot of times, none of those options are satisfactory. Let's take a simple example:
public List<object> MyMethod(List<BHoMObject> elements)
{
List<object> results = new List<object>();
foreach (BHoMObject element in elements)
results.Add(DoSomething(element));
return results;
}
If DoSomething()
throws an exception, this method will fail and pass on the exception. This might be the desired behaviour but we might also want to return all the successful results and just ignore the failing ones. In that case, we could write:
public List<object> MyMethod(List<BHoMObject> elements)
{
List<object> results = new List<object>();
foreach (BHoMObject element in elements)
{
try
{
results.Add(DoSomething(element));
}
catch {}
}
return results;
}
This does the job. But it also hide completely the fact that an error occurred for some of the elements so the results are incomplete.
This is why we have added a log system to the BHoM so all exceptional events can be recorded and passed to the UI.
If we use the log, the code above would look like this:
using BH.Engine.Reflection;
public List<object> MyMethod(List<BHoMObject> elements)
{
List<object> results = new List<object>();
foreach (BHoMObject element in elements)
{
try
{
results.Add(DoSomething(element));
}
catch
{
Compute.RecordWarning("Element " + element.BHoM_Guid + " failed");
}
}
return results;
}
There are 3 levels of event you can record:
- Error:
RecordError()
- Warning:
RecordWarning()
- Note:
RecordNote()
In Grasshopper, they will look like this:
So the UI components will automatically expose all the events that occurred during their execution.
Besides fatal errors, RecordError()
should be used in cases when we are not able to return any result for the provided input:
public static Point Centroid(this PolyCurve curve, double tolerance)
{
if (!curve.IsClosed(tolerance))
{
Reflection.Compute.RecordError("Input curve is not closed. Cannot calculate centroid.");
return null;
}
[...]
}
Note that errors most often go with returning null
(or .NaN
in case of doubles).
RecordWarning()
is for all kind of situations when the result is possible to compute, but we cannot ensure if it is 100% correct. It is also suitable if provided object has been modified in not certainly desired way:
public static Vector Normal(this PolyCurve curve, double tolerance)
{
if (curve.IsSelfIntersecting(tolerance))
Reflection.Compute.RecordWarning("Input curve is self-intersecting. Resulting normal vector might be flipped.");
[...]
}
At last RecordNote()
is meant for the cases when everything run correctly but there is still some info that we would like to communicate to the end user:
public override List<object> Push([...])
{
[...]
if (pushConfig == null)
{
BH.Engine.Reflection.Compute.RecordNote("Revit Push Config has not been specified. Default Revit Push Config is used.");
pushConfig = new RevitPushConfig();
}
[...]
}
As one can see, there is no very strict convention on when to use each level of event. However, these examples should illustrate their intended purpose.
If you want to get the list of all the events that occurred since you started your script/program, you can use BH.Engine.Reflection.Query.AllEvents()
. In Grasshopper, it will look something like this:
As you can see, events are also BHoM object that you can explode as any other typical BHoM object.
Does that mean that we should stop using exception? No!
If your method ends up in a situation where it could not return any meaningful output, it should still throw an exception. Any method that catches an exception, on the other hand, should ALWAYS record something in the Log to make the user aware of what happened.
-
Introduction to the BHoM:
What is the BHoM for?
Structure of the BHoM
Technical Philosophy of the BHoM -
Getting Started:
Installing the BHoM
Using the BHoM
Submitting an Issue
Getting started for developers -
Use GitHub & Visual Studio:
Using the SCRUM Board
Resolving an Issue
Avoiding Conflicts
Creating a new Repository
Using Visual Studio
Using Visual Studio Code -
Contribute:
The oM
The Engine
The Adapter
The Toolkit
The UI
The Tests -
Guidelines:
Unit convention
Geometry
BHoM_Engine Classes
The IImmutable Interface
Handling Exceptional Events
BHoM Structural Conventions
BHoM View Quality Conventions
Code Versioning
Wiki Style
Coding Style
Null Handling
Code Attributes
Creating Icons
Changelog
Releases and Versioning
Open Sourcing Procedure
Dataset guidelines -
Foundational Interfaces:
IElement Required Extension Methods -
Continuous Integration:
Introduction
Check-PR-Builds
Check-Core
Check-Installer -
Code Compliance:
Compliance -
Further Reading:
FAQ
Structural Adapters
Mongo_Toolkit
Socket_Toolkit