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