RefCounted.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // TODO: optimization, remove the static initializer, so we do not need to add code
  3. // at JIT/AOT time to probe for static class initialization
  4. //
  5. using System;
  6. using System.Diagnostics;
  7. using System.Runtime.InteropServices;
  8. namespace Urho {
  9. public partial class RefCounted : IDisposable {
  10. internal IntPtr handle;
  11. public IntPtr Handle => handle;
  12. internal RefCounted (UrhoObjectFlag empty) { }
  13. protected RefCounted (IntPtr handle)
  14. {
  15. if (handle == IntPtr.Zero)
  16. throw new ArgumentException ($"Attempted to instantiate a {GetType()} with a null handle");
  17. this.handle = handle;
  18. Runtime.RegisterObject (this);
  19. }
  20. public void Dispose ()
  21. {
  22. DeleteNativeObject();
  23. Dispose (true);
  24. GC.SuppressFinalize (this);
  25. }
  26. /// <summary>
  27. /// Called by RefCounted::~RefCounted - we don't need to check Refs here - just mark it as deleted and remove from cache
  28. /// </summary>
  29. internal void HandleNativeDelete()
  30. {
  31. Dispose(true);
  32. GC.SuppressFinalize(this);
  33. }
  34. [DllImport(Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
  35. static extern void TryDeleteRefCounted(IntPtr handle);
  36. /// <summary>
  37. /// Try to delete underlying native object if nobody uses it (Refs==0)
  38. /// </summary>
  39. void DeleteNativeObject()
  40. {
  41. if (!IsDeleted)
  42. {
  43. try
  44. {
  45. TryDeleteRefCounted(handle);
  46. }
  47. catch (Exception exc)
  48. {
  49. //should not happen, JIC.
  50. throw new InvalidOperationException("Underlying native object is already deleted", exc);
  51. }
  52. }
  53. }
  54. protected virtual void Dispose (bool disposing)
  55. {
  56. if (IsDeleted)
  57. return;
  58. if (disposing)
  59. {
  60. IsDeleted = true;
  61. OnDeleted();
  62. }
  63. Runtime.UnregisterObject(handle);
  64. }
  65. [Conditional("DEBUG")]
  66. protected void CheckAccess()
  67. {
  68. if (IsDeleted)
  69. throw new InvalidOperationException("The underlying native object was deleted");
  70. if (handle == IntPtr.Zero)
  71. throw new InvalidOperationException("Object has zero handle");
  72. //TODO: check thread
  73. }
  74. protected void CheckEngine()
  75. {
  76. UrhoPlatformInitializer.DefaultInit();
  77. }
  78. /// <summary>
  79. /// True if underlying native object is deleted
  80. /// </summary>
  81. public bool IsDeleted { get; private set; }
  82. protected virtual void OnDeleted() { }
  83. public override bool Equals (object other)
  84. {
  85. if (other == null)
  86. return false;
  87. if (other.GetType () != GetType ())
  88. return false;
  89. var or = other as RefCounted;
  90. if (or != null && or.handle == handle)
  91. return true;
  92. return false;
  93. }
  94. public static bool operator ==(RefCounted _a, RefCounted _b)
  95. {
  96. object a = _a;
  97. object b = _b;
  98. if (a == null){
  99. if (b == null)
  100. return true;
  101. return false;
  102. } else {
  103. if (b == null)
  104. return false;
  105. return _a.handle == _b.handle;
  106. }
  107. }
  108. public static bool operator !=(RefCounted _a, RefCounted _b)
  109. {
  110. object a = _a;
  111. object b = _b;
  112. if (a == null)
  113. return b != null;
  114. else {
  115. if (b == null)
  116. return true;
  117. return _a.handle != _b.handle;
  118. }
  119. }
  120. public override int GetHashCode ()
  121. {
  122. if (IntPtr.Size == 8) //means 64bit
  123. return unchecked ((int) (long) handle);
  124. return (int) handle;
  125. }
  126. ~RefCounted ()
  127. {
  128. DeleteNativeObject();
  129. Dispose (false);
  130. }
  131. }
  132. }