Is it possible to detect a property change at runtime?

Meaning... if someone changes the color property of a script in the Inspector at runtime, is there a way to detect that event?

you can "detect" it by saving the value constantly and compare it with its actual value like

color oldColor;
color newColor;
update()
{
newColor = object.color;
if(oldColor!= newColor)
{
Debug.log("The color change was realized");
}
oldColor = object.color;
}

thats one way to see the change, hope this helps you

This actually isn’t a valid solution due to floating point precision issues (trust me, I’ve been at this for a full day now). I’m working on a method that will compare a specific precision of the float for each rgba channel in two colors, but I’m trying to make it quick enough that the compare isn’t detrimental when run in Update().

I’ve also seen a recommendation to use inverselerp, but that seems costly in Update() or FixedUpdate()

This is what I just coded up that works really well and simple to use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

public class PropertyNotifier<T>
{
	object Instance;
	FieldInfo Field;
	MethodInfo OnChangedMethod;

	public PropertyNotifier(object propertyObject, string fieldName)
	{
		// verify object
		Instance = propertyObject;

		// pull field for the property on the object
		Field = Instance.GetType().GetField(fieldName);
		if (Field == null)
			throw new Exception(Instance.GetType().Name + "." + fieldName + " not found!");

		// pull changed method for the property on the object
		var changedMethodName = "On" + fieldName + "Changed";
		OnChangedMethod = Instance.GetType().GetMethod(changedMethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (OnChangedMethod == null)
			throw new Exception(Instance.GetType().Name + "." + changedMethodName + " not found.  Please create it!");
	}

	public void Set(T value)
	{
		T currentValue = (T)Field.GetValue(Instance);
		if (currentValue == null && value == null)
			return;
		if (currentValue != null && value != null && currentValue.Equals(value))
			return;
		Field.SetValue(Instance, value);
		OnChangedMethod.Invoke(Instance, null);
	}

	public void ForceNotification()
	{
		OnChangedMethod.Invoke(Instance, null);
	}
}

public class TestClass
{
	public int IntField;
	PropertyNotifier<int> IntProperty;

	public string StrField;
	PropertyNotifier<string> StrProperty;

	public TestClass()
	{
		IntProperty = new PropertyNotifier<int>(this, "IntField");
		StrProperty = new PropertyNotifier<string>(this, "StrField");

		IntProperty.Set(5);
		IntProperty.Set(6);
		IntProperty.Set(6);
		IntProperty.Set(7);

		StrProperty.Set(null);
		StrProperty.Set("hello");
		StrProperty.Set("hello");
		StrProperty.Set("world");
		StrProperty.Set(null);
	}

	void OnIntFieldChanged()
	{
		System.Diagnostics.Debug.WriteLine("OnIntMemberChanged to " + IntField);
	}

	void OnStrFieldChanged()
	{
		System.Diagnostics.Debug.WriteLine("OnStrMemberChanged to " + (string.IsNullOrEmpty(StrField) ? "nullOrEmpty" : StrField));
	}
}

It produces the following output:

OnIntMemberChanged to 5
OnIntMemberChanged to 6
OnIntMemberChanged to 7
OnStrMemberChanged to hello
OnStrMemberChanged to world
OnStrMemberChanged to nullOrEmpty