using System; using System.Diagnostics; using System.Reflection; namespace IPA.Utilities { /// /// Utilities to create using type inference. /// public static class Ref { /// /// Creates a . /// /// the type to reference. /// the default value. /// the new . public static Ref Create(T val) { return new Ref(val); } } /// /// A class to store a reference for passing to methods which cannot take ref parameters. /// /// the type of the value public class Ref : IComparable, IComparable> { private T _value; /// /// The value of the reference /// /// the value wrapped by this 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. /// /// the error held in this 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; } /// /// Converts to referenced type, returning the stored reference. /// /// the object to be de-referenced /// the value referenced by the object public static implicit operator T(Ref self) { return self.Value; } /// /// Converts a value T to a reference to that object. Will overwrite the reference in the left hand expression if there is one. /// /// the value to wrap in the Ref /// the Ref wrapping the value public static implicit operator Ref(T toConvert) { return new Ref(toConvert); } /// /// Throws error if one was set. /// public void Verify() { if (Error != null) throw Error; } /// /// Compares the wrapped object to the other object. /// /// the object to compare to /// the value of the comparison public int CompareTo(T other) { if (Value is IComparable compare) return compare.CompareTo(other); return Equals(Value, other) ? 0 : -1; } /// /// Compares the wrapped object to the other wrapped object. /// /// the wrapped object to compare to /// the value of the comparison public int CompareTo(Ref other) => CompareTo(other.Value); } 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; } } }