using System; using System.Collections.Generic; using System.Dynamic; namespace Python.Test; /// /// Base class for dynamic test helpers. Uses lazy storage initialization so that /// Python-derived subclasses can safely call DynamicObject member hooks before /// managed field initializers have run. /// public class DynamicStorageObject : DynamicObject { Dictionary storage; // Python-defined subclasses may reach this type without running managed field // initializers (see ClassDerivedObject.NewObjectToPython). Via the lazy init // we can ensure that the access is still safe, even when the constructor has // not run. protected Dictionary Storage => storage ??= []; public void AddDynamicMember(string name, object value) => Storage[name] = value; public override bool TryGetMember(GetMemberBinder binder, out object result) => Storage.TryGetValue(binder.Name, out result); public override bool TrySetMember(SetMemberBinder binder, object value) { Storage[binder.Name] = value; return true; } public override bool TryDeleteMember(DeleteMemberBinder binder) => Storage.Remove(binder.Name); public override IEnumerable GetDynamicMemberNames() => Storage.Keys; } public class DynamicMappingObject : DynamicStorageObject { // Native members for testing that regular CLR access is unaffected. public string Label = "default"; public int Multiplier { get; set; } = 1; public int Multiply(int value) => value * Multiplier; // Test helper: bypass normal member binding and write directly to dynamic storage. public void SetDynamicValue(string name, object value) => Storage[name] = value; // Test helper: retrieve the actual value stored in C# (for verification that None was stored as null) public object GetDynamicValue(string name) => Storage.TryGetValue(name, out var value) ? value : null; } public class RejectingSetDynamicObject : DynamicStorageObject { public override bool TrySetMember(SetMemberBinder binder, object value) { if (!Storage.ContainsKey(binder.Name)) return false; Storage[binder.Name] = value; return true; } } public class ThrowingGetDynamicObject : DynamicStorageObject { public override bool TryGetMember(GetMemberBinder binder, out object result) => throw new InvalidOperationException($"TryGetMember failed for '{binder.Name}'"); } public class ThrowingSetDynamicObject : DynamicStorageObject { public override bool TrySetMember(SetMemberBinder binder, object value) => throw new InvalidOperationException($"TrySetMember failed for '{binder.Name}'"); } public class RejectingDeleteDynamicObject : DynamicStorageObject { public override bool TryDeleteMember(DeleteMemberBinder binder) { if (!Storage.ContainsKey(binder.Name)) return false; return Storage.Remove(binder.Name); } } public class ThrowingDeleteDynamicObject : DynamicStorageObject { public override bool TryDeleteMember(DeleteMemberBinder binder) => throw new InvalidOperationException($"TryDeleteMember failed for '{binder.Name}'"); }