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;
}
}
}
]