using System; using System.Diagnostics; using System.Reflection; namespace IPA.Utilities { /// /// A class to store a reference for passing to methods which cannot take ref parameters. /// /// the type of the value public class Ref { private T _value; /// /// The value of the reference /// public T Value { get { if (Error != null) throw Error; return _value; } set => _value = value; } private Exception _error; /// /// An exception that was generated while creating the value. /// public Exception Error { get { return _error; } set { value.SetStackTrace(new StackTrace(1)); _error = value; } } /// /// Constructor. /// /// the initial value of the reference public Ref(T reference) { _value = reference; } /// /// Throws error if one was set. /// public void Verify() { if (Error != null) throw new Exception("Found error", Error); } } internal static class ExceptionUtilities { private static readonly FieldInfo StackTraceStringFi = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance); private static readonly Type TraceFormatTi = Type.GetType("System.Diagnostics.StackTrace")?.GetNestedType("TraceFormat", BindingFlags.NonPublic); private static readonly MethodInfo TraceToStringMi = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { TraceFormatTi }, null); public static Exception SetStackTrace(this Exception target, StackTrace stack) { var getStackTraceString = TraceToStringMi.Invoke(stack, new[] { Enum.GetValues(TraceFormatTi).GetValue(0) }); StackTraceStringFi.SetValue(target, getStackTraceString); return target; } } }