You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
2.3 KiB

  1. using System;
  2. using System.Diagnostics;
  3. using System.Reflection;
  4. namespace IPA.Utilities
  5. {
  6. /// <summary>
  7. /// A class to store a reference for passing to methods which cannot take ref parameters.
  8. /// </summary>
  9. /// <typeparam name="T">the type of the value</typeparam>
  10. public class Ref<T>
  11. {
  12. private T _value;
  13. /// <summary>
  14. /// The value of the reference
  15. /// </summary>
  16. public T Value
  17. {
  18. get
  19. {
  20. if (Error != null) throw Error;
  21. return _value;
  22. }
  23. set => _value = value;
  24. }
  25. private Exception _error;
  26. /// <summary>
  27. /// An exception that was generated while creating the value.
  28. /// </summary>
  29. public Exception Error
  30. {
  31. get
  32. {
  33. return _error;
  34. }
  35. set
  36. {
  37. value.SetStackTrace(new StackTrace(1));
  38. _error = value;
  39. }
  40. }
  41. /// <summary>
  42. /// Constructor.
  43. /// </summary>
  44. /// <param name="reference">the initial value of the reference</param>
  45. public Ref(T reference)
  46. {
  47. _value = reference;
  48. }
  49. /// <summary>
  50. /// Throws error if one was set.
  51. /// </summary>
  52. public void Verify()
  53. {
  54. if (Error != null) throw new Exception("Found error", Error);
  55. }
  56. }
  57. internal static class ExceptionUtilities
  58. {
  59. private static readonly FieldInfo StackTraceStringFi = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
  60. private static readonly Type TraceFormatTi = Type.GetType("System.Diagnostics.StackTrace")?.GetNestedType("TraceFormat", BindingFlags.NonPublic);
  61. private static readonly MethodInfo TraceToStringMi = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { TraceFormatTi }, null);
  62. public static Exception SetStackTrace(this Exception target, StackTrace stack)
  63. {
  64. var getStackTraceString = TraceToStringMi.Invoke(stack, new[] { Enum.GetValues(TraceFormatTi).GetValue(0) });
  65. StackTraceStringFi.SetValue(target, getStackTraceString);
  66. return target;
  67. }
  68. }
  69. }