Skip to content

Instantly share code, notes, and snippets.

@gotmachine
Created May 20, 2022 11:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gotmachine/c2d0f09c6eeb86a89256978a9ee7ff5e to your computer and use it in GitHub Desktop.
Save gotmachine/c2d0f09c6eeb86a89256978a9ee7ff5e to your computer and use it in GitHub Desktop.
Extension methods for easier, faster more clear null and destroyed state checking for UnityEngine.Object
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
#pragma warning disable IDE0041 // Use 'is null' check
namespace UnityObjectNullExtensions
{
public static class UnityObjectNullExtensionsSafe
{
private static Func<UnityEngine.Object, IntPtr> getNativeObjPtr;
static UnityObjectNullExtensionsSafe()
{
Type unityObjectType = typeof(UnityEngine.Object);
FieldInfo fInfo = unityObjectType.GetField("m_CachedPtr", BindingFlags.Instance | BindingFlags.NonPublic);
ParameterExpression objParm = Expression.Parameter(unityObjectType, "obj");
Type delegateType = typeof(Func<,>).MakeGenericType(unityObjectType, typeof(IntPtr));
MemberExpression fieldExpr = Expression.Field(objParm, fInfo);
LambdaExpression lambda = Expression.Lambda(delegateType, fieldExpr, objParm);
getNativeObjPtr = (Func<UnityEngine.Object, IntPtr>)lambda.Compile();
}
/// <summary>
/// True if this <paramref name="unityObject"/> instance is destroyed or not yet initialized.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDestroyed(this UnityEngine.Object unityObject)
{
return getNativeObjPtr(unityObject) == IntPtr.Zero;
}
/// <summary>
/// True if this <paramref name="unityObject"/> reference is <c>null</c>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNull(this UnityEngine.Object unityObject)
{
return ReferenceEquals(unityObject, null);
}
/// <summary>
/// True if this <paramref name="unityObject"/> reference is <c>null</c> or if the instance is destroyed<br/>
/// Equivalent as testing <c><paramref name="unityObject"/> == null</c> but several times faster.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrDestroyed(this UnityEngine.Object unityObject)
{
return ReferenceEquals(unityObject, null) || getNativeObjPtr(unityObject) == IntPtr.Zero;
}
/// <summary>
/// Return <c>null</c> when this <paramref name="unityObject"/> reference is null or destroyed, otherwise return the <paramref name="unityObject"/> instance<br/>
/// Allow using null conditional and null coalescing operators with UnityEngine.Object derivatives while conforming to the "a destroyed object is equal to null" Unity concept.<br/>
/// Example :<br/>
/// <c>float x = myUnityObject.DestroyedAsNull()?.myFloatField ?? 0f;</c><br/>
/// will evaluate to <c>0f</c> when <c>myUnityObject</c> is destroyed, instead of returning the value still available on the managed instance.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T DestroyedAsNull<T>(this T unityObject) where T : UnityEngine.Object
{
if (ReferenceEquals(unityObject, null) || getNativeObjPtr(unityObject) == IntPtr.Zero)
return null;
return unityObject;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment