RefCounted.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. using Urho.IO;
  9. namespace Urho {
  10. public partial class RefCounted : IDisposable {
  11. internal IntPtr handle;
  12. public IntPtr Handle => handle;
  13. [Preserve]
  14. internal RefCounted (UrhoObjectFlag empty) { }
  15. [Preserve]
  16. protected RefCounted (IntPtr handle)
  17. {
  18. if (handle == IntPtr.Zero)
  19. throw new ArgumentException ($"Attempted to instantiate a {GetType()} with a null handle");
  20. this.handle = handle;
  21. Runtime.RegisterObject (this);
  22. }
  23. public void Dispose ()
  24. {
  25. DeleteNativeObject();
  26. Dispose (true);
  27. GC.SuppressFinalize (this);
  28. }
  29. /// <summary>
  30. /// Called by RefCounted::~RefCounted - we don't need to check Refs here - just mark it as deleted and remove from cache
  31. /// </summary>
  32. internal void HandleNativeDelete()
  33. {
  34. LogSharp.Trace($"{GetType().Name}: HandleNativeDelete");
  35. Dispose(true);
  36. GC.SuppressFinalize(this);
  37. }
  38. [DllImport(Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
  39. static extern void TryDeleteRefCounted(IntPtr handle);
  40. /// <summary>
  41. /// Try to delete underlying native object if nobody uses it (Refs==0)
  42. /// </summary>
  43. void DeleteNativeObject()
  44. {
  45. if (!IsDeleted && AllowNativeDelete)
  46. {
  47. LogSharp.Trace($"{GetType().Name}: DeleteNativeObject");
  48. TryDeleteRefCounted(handle);
  49. }
  50. }
  51. protected virtual void Dispose (bool disposing)
  52. {
  53. if (IsDeleted)
  54. return;
  55. if (disposing)
  56. {
  57. IsDeleted = true;
  58. OnDeleted();
  59. }
  60. Runtime.UnregisterObject(handle);
  61. }
  62. protected void CheckEngine()
  63. {
  64. UrhoPlatformInitializer.DefaultInit();
  65. }
  66. /// <summary>
  67. /// True if underlying native object is deleted
  68. /// </summary>
  69. public bool IsDeleted { get; private set; }
  70. protected virtual void OnDeleted() { }
  71. protected virtual bool AllowNativeDelete => true;
  72. public override bool Equals (object other)
  73. {
  74. if (other == null)
  75. return false;
  76. if (other.GetType () != GetType ())
  77. return false;
  78. var or = other as RefCounted;
  79. if (or != null && or.handle == handle)
  80. return true;
  81. return false;
  82. }
  83. public static bool operator ==(RefCounted _a, RefCounted _b)
  84. {
  85. object a = _a;
  86. object b = _b;
  87. if (a == null){
  88. if (b == null)
  89. return true;
  90. return false;
  91. } else {
  92. if (b == null)
  93. return false;
  94. return _a.handle == _b.handle;
  95. }
  96. }
  97. public static bool operator !=(RefCounted _a, RefCounted _b)
  98. {
  99. object a = _a;
  100. object b = _b;
  101. if (a == null)
  102. return b != null;
  103. else {
  104. if (b == null)
  105. return true;
  106. return _a.handle != _b.handle;
  107. }
  108. }
  109. public override int GetHashCode ()
  110. {
  111. if (IntPtr.Size == 8) //means 64bit
  112. return unchecked ((int) (long) handle);
  113. return (int) handle;
  114. }
  115. ~RefCounted ()
  116. {
  117. if (!Runtime.IsClosing && !IsDeleted)
  118. {
  119. var ptr = Handle;
  120. Application.InvokeOnMain(() => TryDeleteRefCounted(ptr));
  121. }
  122. Dispose (false);
  123. }
  124. }
  125. }