using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace OpenTap { /// Mixin member data public class MixinMemberData : IMemberData, IDynamicMemberData { /// Attributes public IEnumerable Attributes { get; set; } = Array.Empty(); /// Name of the member public string Name { get; set; } /// Declaring type. This should be the type of the target object. public ITypeData DeclaringType { get; set; } /// Describes the value of the member. public ITypeData TypeDescriptor { get; set; } /// If the member is writable. public bool Writable { get; set; } /// If the member is readable. This should generally be true. public bool Readable { get; set; } readonly ConditionalWeakTable dict = new ConditionalWeakTable(); readonly Func make; /// Sets the value of the member. public virtual void SetValue(object owner, object value) { dict.Remove(owner); dict.GetValue(owner, owner => value); } /// Gets the value of the member. public virtual object GetValue(object owner) { if (dict.TryGetValue(owner, out var value)) return value; return DefaultValue; } /// The default value of the member. public object DefaultValue { get; set; } /// The object which was used to construct this. public IMixinBuilder Source { get; } internal object NewInstance() { if (DefaultValue != null) return DefaultValue; if (TypeDescriptor.DescendsTo(typeof(string))) return null; if (make != null) return make(); return TypeDescriptor.CreateInstance(); } /// Creates a new instance of mixin member data. public MixinMemberData(IMixinBuilder source, Func make = null) { this.make = make; Writable = true; Readable = true; Source = source; } bool isDisposed = false; bool IDynamicMemberData.IsDisposed => isDisposed; // declare that this member data has been removed. // this is important for parameterized mixin member data. internal void Dispose() { isDisposed = true; } /// Creates a string representation of this mixin member data public override string ToString() { return $"MixinMemberData: {Name}"; } } }