Files
pardeike-Harmony/Documentation/examples/execution_with.cs

84 lines
2.1 KiB
C#

namespace Execution_With
{
using System;
#pragma warning disable CS9113
public class Code
{
// <example>
static R ReplacementMethod(T optionalThisArgument /*, ... arguments ... */ )
{
R result = default;
var finalized = false;
Exception ex = null;
// All this code is generated dynamically, which means that
// Harmony can build it depending on
//
// - if there are any finalizers (otherwise, skip try-catch)
//
// - re-throwing can be dynamic too depending on if at least
// one finalizer returns a non-void result
try
{
result = Original(/* ... arguments ... */);
// finalizers get all the arguments a prefix could get too
// plus one new one: "Exception __exception"
// they SHOULD NOT edit the passed exception but instead
// signal to Harmony that they change it by returning it
// here finalizers are called without try-catch so they are
// allowed to throw exceptions. note, that it is perfectly
// fine to get null passed into the exception argument
SimpleFinalizer(ref result);
ex = EditFinalizer(ex, ref result);
finalized = true;
if (ex is not null) throw ex;
return result;
}
catch (Exception e)
{
ex = e;
// finalizers will get another chance here, so they are
// guaranteed to run even if their first invocation threw
// an exception
if (!finalized)
{
try { SimpleFinalizer(ref result); } catch { }
try { ex = EditFinalizer(ex, ref result); } catch { }
}
if (allVoid)
{
// alternative 1: all finalizers are returning void
throw;
}
else
{
// alternative 2: at least one non-void finalizer
if (ex is not null) throw ex;
}
return result;
}
}
// given the following signatures:
public static R Original() => new("original");
public static void SimpleFinalizer(ref R result) { }
public static Exception EditFinalizer(Exception ex, ref R result) => ex;
// </example>
public class R(string s) { }
public class T { }
public static bool allVoid;
}
#pragma warning restore CS9113
}