// https://github.com/XtraCube/Reactor/blob/main/Reactor/Utilities/CompilerGeneratedObjectWrapper.cs using System; using System.Collections.Generic; using System.Reflection; using HarmonyLib; namespace EHR.Modules; /// /// A safe wrapper around compiler generated classes like DisplayClass or IEnumerator state machines. /// public class CompilerGeneratedObjectWrapper { /// /// Gets a reference to the compiler generated object. /// public object GeneratedObject { get; } /// /// Gets the type of the compiler generated object. /// protected Type GeneratedType { get; } /// /// Gets the property info cache for faster lookups. /// protected Dictionary PropertyCache { get; } /// /// Initializes a new instance of the class. /// /// An instance of the compiler generated object. public CompilerGeneratedObjectWrapper(object generatedObject) { GeneratedObject = generatedObject; GeneratedType = generatedObject.GetType(); PropertyCache = []; } /// /// Gets the value of a field in the compiler generated object. /// /// The name of the field to get. /// The type of the field. /// >The value of the field. /// Thrown if the field does not exist. public TField GetField(string fieldName) { if (!PropertyCache.TryGetValue(fieldName, out var propertyInfo)) { propertyInfo = AccessTools.Property(GeneratedType, fieldName); if (propertyInfo == null) { throw new MissingMemberException($"Could not find field '{fieldName}' in type '{GeneratedType}'."); } PropertyCache[fieldName] = propertyInfo; } return (TField) propertyInfo.GetValue(GeneratedObject)!; } /// /// Sets the value of a field in the compiler generated object. /// /// The name of the field to set. /// The value to set. /// The type of the field. /// Thrown if the field does not exist. public void SetField(string fieldName, TField value) { if (!PropertyCache.TryGetValue(fieldName, out var propertyInfo)) { propertyInfo = AccessTools.Property(GeneratedType, fieldName); if (propertyInfo == null) { throw new MissingMemberException($"Could not find field '{fieldName}' in type '{GeneratedType}'."); } PropertyCache[fieldName] = propertyInfo; } propertyInfo.SetValue(GeneratedObject, value); } }