RefCounted.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. if (!Application.EngineInited)
  77. {
  78. throw new InvalidOperationException("The engine is not inited. Please call UrhoEngine.Init().");
  79. }
  80. }
  81. /// <summary>
  82. /// True if underlying native object is deleted
  83. /// </summary>
  84. public bool IsDeleted { get; private set; }
  85. protected virtual void OnDeleted() { }
  86. public override bool Equals (object other)
  87. {
  88. if (other == null)
  89. return false;
  90. if (other.GetType () != GetType ())
  91. return false;
  92. var or = other as RefCounted;
  93. if (or != null && or.handle == handle)
  94. return true;
  95. return false;
  96. }
  97. public static bool operator ==(RefCounted _a, RefCounted _b)
  98. {
  99. object a = _a;
  100. object b = _b;
  101. if (a == null){
  102. if (b == null)
  103. return true;
  104. return false;
  105. } else {
  106. if (b == null)
  107. return false;
  108. return _a.handle == _b.handle;
  109. }
  110. }
  111. public static bool operator !=(RefCounted _a, RefCounted _b)
  112. {
  113. object a = _a;
  114. object b = _b;
  115. if (a == null)
  116. return b != null;
  117. else {
  118. if (b == null)
  119. return true;
  120. return _a.handle != _b.handle;
  121. }
  122. }
  123. public override int GetHashCode ()
  124. {
  125. if (IntPtr.Size == 8) //means 64bit
  126. return unchecked ((int) (long) handle);
  127. return (int) handle;
  128. }
  129. ~RefCounted ()
  130. {
  131. DeleteNativeObject();
  132. Dispose (false);
  133. }
  134. }
  135. }