using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text; using Unity.Collections.LowLevel.Unsafe; using Unity.Properties.Internal; using UnityEngine; using UnityEngine.Bindings; using UnityEngine.Pool; using UnityEngine.Scripting; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: InternalsVisibleTo("UnityEngine")] [assembly: UnityEngineModuleAssembly] [assembly: InternalsVisibleTo("UnityEditor.PropertiesModule")] [assembly: InternalsVisibleTo("PropertyBags.GenerationTests")] [assembly: InternalsVisibleTo("Unity.Properties.Reflection.Tests")] [assembly: InternalsVisibleTo("Unity.Properties.Tests")] [assembly: InternalsVisibleTo("UnityEngine.UIElementsModule")] [assembly: InternalsVisibleTo("UnityEditor.UIElementsModule")] [assembly: InternalsVisibleTo("Unity.Properties.CodeGen.IntegrationTests")] [assembly: InternalsVisibleTo("Unity.UIElements.RuntimeTests")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace Unity.Properties { [Flags] public enum VisitExceptionKind { None = 0, Internal = 1, Visitor = 2, All = 3 } public struct VisitParameters { public VisitExceptionKind IgnoreExceptions { get; set; } } public static class PropertyContainer { private class GetPropertyVisitor : PathVisitor { public static readonly ObjectPool Pool = new ObjectPool((Func)(() => new GetPropertyVisitor()), (Action)null, (Action)delegate(GetPropertyVisitor v) { v.Reset(); }, (Action)null, true, 10, 10000); public IProperty Property; public override void Reset() { base.Reset(); Property = null; base.ReadonlyVisit = true; } protected override void VisitPath(Property property, ref TContainer container, ref TValue value) { Property = property; } } private class GetValueVisitor : PathVisitor { public static readonly ObjectPool> Pool = (ObjectPool>)(object)new ObjectPool>>((Func>>)(object)(Func>)(() => new GetValueVisitor()), (Action>>)null, (Action>>)(Action>)delegate(GetValueVisitor v) { v.Reset(); }, (Action>>)null, true, 10, 10000); public TSrcValue Value; public override void Reset() { base.Reset(); Value = default(TSrcValue); base.ReadonlyVisit = true; } protected override void VisitPath(Property property, ref TContainer container, ref TValue value) { if (!TypeConversion.TryConvert(ref value, out Value)) { base.ReturnCode = VisitReturnCode.InvalidCast; } } } private class ValueAtPathVisitor : PathVisitor { public static readonly ObjectPool Pool = new ObjectPool((Func)(() => new ValueAtPathVisitor()), (Action)null, (Action)delegate(ValueAtPathVisitor v) { v.Reset(); }, (Action)null, true, 10, 10000); public IPropertyVisitor Visitor; public override void Reset() { base.Reset(); Visitor = null; base.ReadonlyVisit = true; } protected override void VisitPath(Property property, ref TContainer container, ref TValue value) { ((IPropertyAccept)property).Accept(Visitor, ref container); } } private class ExistsAtPathVisitor : PathVisitor { public static readonly ObjectPool Pool = new ObjectPool((Func)(() => new ExistsAtPathVisitor()), (Action)null, (Action)delegate(ExistsAtPathVisitor v) { v.Reset(); }, (Action)null, true, 10, 10000); public bool Exists; public override void Reset() { base.Reset(); Exists = false; base.ReadonlyVisit = true; } protected override void VisitPath(Property property, ref TContainer container, ref TValue value) { Exists = true; } } internal class SetValueVisitor : PathVisitor { public static readonly ObjectPool> Pool = (ObjectPool>)(object)new ObjectPool>>((Func>>)(object)(Func>)(() => new SetValueVisitor()), (Action>>)null, (Action>>)(Action>)delegate(SetValueVisitor v) { v.Reset(); }, (Action>>)null, true, 10, 10000); public TSrcValue Value; public override void Reset() { base.Reset(); Value = default(TSrcValue); } protected override void VisitPath(Property property, ref TContainer container, ref TValue value) { TValue destination; if (property.IsReadOnly) { base.ReturnCode = VisitReturnCode.AccessViolation; } else if (TypeConversion.TryConvert(ref Value, out destination)) { property.SetValue(ref container, destination); } else { base.ReturnCode = VisitReturnCode.InvalidCast; } } } public static void Accept(IPropertyBagVisitor visitor, TContainer container, VisitParameters parameters = default(VisitParameters)) { VisitReturnCode returnCode = VisitReturnCode.Ok; try { if (TryAccept(visitor, ref container, out returnCode, parameters)) { return; } } catch (Exception) { if ((parameters.IgnoreExceptions & VisitExceptionKind.Visitor) == 0) { throw; } } if ((parameters.IgnoreExceptions & VisitExceptionKind.Internal) == 0) { switch (returnCode) { case VisitReturnCode.Ok: case VisitReturnCode.InvalidContainerType: break; case VisitReturnCode.NullContainer: throw new ArgumentException("The given container was null. Visitation only works for valid non-null containers."); case VisitReturnCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", returnCode)); } } } public static void Accept(IPropertyBagVisitor visitor, ref TContainer container, VisitParameters parameters = default(VisitParameters)) { VisitReturnCode returnCode = VisitReturnCode.Ok; try { if (TryAccept(visitor, ref container, out returnCode, parameters)) { return; } } catch (Exception) { if ((parameters.IgnoreExceptions & VisitExceptionKind.Visitor) == 0) { throw; } } if ((parameters.IgnoreExceptions & VisitExceptionKind.Internal) == 0) { switch (returnCode) { case VisitReturnCode.Ok: case VisitReturnCode.InvalidContainerType: break; case VisitReturnCode.NullContainer: throw new ArgumentException("The given container was null. Visitation only works for valid non-null containers."); case VisitReturnCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", returnCode)); } } } public static bool TryAccept(IPropertyBagVisitor visitor, ref TContainer container, VisitParameters parameters = default(VisitParameters)) { VisitReturnCode returnCode; return TryAccept(visitor, ref container, out returnCode, parameters); } public static bool TryAccept(IPropertyBagVisitor visitor, ref TContainer container, out VisitReturnCode returnCode, VisitParameters parameters = default(VisitParameters)) { if (!TypeTraits.IsContainer) { returnCode = VisitReturnCode.InvalidContainerType; return false; } if (TypeTraits.CanBeNull && EqualityComparer.Default.Equals(container, default(TContainer))) { returnCode = VisitReturnCode.NullContainer; return false; } if (!TypeTraits.IsValueType && typeof(TContainer) != container.GetType()) { if (!TypeTraits.IsContainer(container.GetType())) { returnCode = VisitReturnCode.InvalidContainerType; return false; } IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(container.GetType()); if (propertyBag == null) { returnCode = VisitReturnCode.MissingPropertyBag; return false; } object container2 = container; propertyBag.Accept(visitor, ref container2); container = (TContainer)container2; } else { IPropertyBag propertyBag2 = PropertyBagStore.GetPropertyBag(); if (propertyBag2 == null) { returnCode = VisitReturnCode.MissingPropertyBag; return false; } PropertyBag.AcceptWithSpecializedVisitor(propertyBag2, visitor, ref container); } returnCode = VisitReturnCode.Ok; return true; } public static void Accept(IPropertyVisitor visitor, ref TContainer container, in PropertyPath path, VisitParameters parameters = default(VisitParameters)) { ValueAtPathVisitor valueAtPathVisitor = ValueAtPathVisitor.Pool.Get(); try { valueAtPathVisitor.Path = path; valueAtPathVisitor.Visitor = visitor; Accept(valueAtPathVisitor, ref container, parameters); if ((parameters.IgnoreExceptions & VisitExceptionKind.Internal) == 0) { switch (valueAtPathVisitor.ReturnCode) { case VisitReturnCode.Ok: break; case VisitReturnCode.InvalidPath: throw new InvalidPathException($"Failed to Visit at Path=[{path}]"); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", valueAtPathVisitor.ReturnCode)); } } } finally { ValueAtPathVisitor.Pool.Release(valueAtPathVisitor); } } public static bool TryAccept(IPropertyVisitor visitor, ref TContainer container, in PropertyPath path, out VisitReturnCode returnCode, VisitParameters parameters = default(VisitParameters)) { ValueAtPathVisitor valueAtPathVisitor = ValueAtPathVisitor.Pool.Get(); try { valueAtPathVisitor.Path = path; valueAtPathVisitor.Visitor = visitor; return TryAccept(valueAtPathVisitor, ref container, out returnCode, parameters); } finally { ValueAtPathVisitor.Pool.Release(valueAtPathVisitor); } } public static IProperty GetProperty(TContainer container, in PropertyPath path) { return GetProperty(ref container, in path); } public static IProperty GetProperty(ref TContainer container, in PropertyPath path) { if (TryGetProperty(ref container, in path, out var property, out var returnCode)) { return property; } switch (returnCode) { case VisitReturnCode.NullContainer: throw new ArgumentNullException("container"); case VisitReturnCode.InvalidContainerType: throw new InvalidContainerTypeException(container.GetType()); case VisitReturnCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); case VisitReturnCode.InvalidPath: throw new ArgumentException($"Failed to get property for path=[{path}]"); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", returnCode)); } } public static bool TryGetProperty(TContainer container, in PropertyPath path, out IProperty property) { VisitReturnCode returnCode; return TryGetProperty(ref container, in path, out property, out returnCode); } public static bool TryGetProperty(ref TContainer container, in PropertyPath path, out IProperty property) { VisitReturnCode returnCode; return TryGetProperty(ref container, in path, out property, out returnCode); } public static bool TryGetProperty(ref TContainer container, in PropertyPath path, out IProperty property, out VisitReturnCode returnCode) { GetPropertyVisitor getPropertyVisitor = GetPropertyVisitor.Pool.Get(); try { getPropertyVisitor.Path = path; if (!TryAccept(getPropertyVisitor, ref container, out returnCode)) { property = null; return false; } returnCode = getPropertyVisitor.ReturnCode; property = getPropertyVisitor.Property; return returnCode == VisitReturnCode.Ok; } finally { GetPropertyVisitor.Pool.Release(getPropertyVisitor); } } public static TValue GetValue(TContainer container, string name) { return GetValue(ref container, name); } public static TValue GetValue(ref TContainer container, string name) { return GetValue(ref container, new PropertyPath(name)); } public static TValue GetValue(TContainer container, in PropertyPath path) { return GetValue(ref container, in path); } public static TValue GetValue(ref TContainer container, in PropertyPath path) { if (path.IsEmpty) { throw new InvalidPathException("The specified PropertyPath is empty."); } if (TryGetValue(ref container, in path, out var value, out var returnCode)) { return value; } switch (returnCode) { case VisitReturnCode.NullContainer: throw new ArgumentNullException("container"); case VisitReturnCode.InvalidContainerType: throw new InvalidContainerTypeException(container.GetType()); case VisitReturnCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); case VisitReturnCode.InvalidCast: throw new InvalidCastException($"Failed to GetValue of Type=[{typeof(TValue).Name}] for property with path=[{path}]"); case VisitReturnCode.InvalidPath: throw new InvalidPathException($"Failed to GetValue for property with Path=[{path}]"); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", returnCode)); } } public static bool TryGetValue(TContainer container, string name, out TValue value) { return TryGetValue(ref container, name, out value); } public static bool TryGetValue(ref TContainer container, string name, out TValue value) { VisitReturnCode returnCode; return TryGetValue(ref container, new PropertyPath(name), out value, out returnCode); } public static bool TryGetValue(TContainer container, in PropertyPath path, out TValue value) { VisitReturnCode returnCode; return TryGetValue(ref container, in path, out value, out returnCode); } public static bool TryGetValue(ref TContainer container, in PropertyPath path, out TValue value) { VisitReturnCode returnCode; return TryGetValue(ref container, in path, out value, out returnCode); } public static bool TryGetValue(ref TContainer container, in PropertyPath path, out TValue value, out VisitReturnCode returnCode) { if (path.IsEmpty) { returnCode = VisitReturnCode.InvalidPath; value = default(TValue); return false; } GetValueVisitor getValueVisitor = GetValueVisitor.Pool.Get(); getValueVisitor.Path = path; getValueVisitor.ReadonlyVisit = true; try { if (!TryAccept(getValueVisitor, ref container, out returnCode)) { value = default(TValue); return false; } value = getValueVisitor.Value; returnCode = getValueVisitor.ReturnCode; } finally { GetValueVisitor.Pool.Release(getValueVisitor); } return returnCode == VisitReturnCode.Ok; } public static bool IsPathValid(TContainer container, string path) { return IsPathValid(ref container, new PropertyPath(path)); } public static bool IsPathValid(TContainer container, in PropertyPath path) { return IsPathValid(ref container, in path); } public static bool IsPathValid(ref TContainer container, string path) { ExistsAtPathVisitor existsAtPathVisitor = ExistsAtPathVisitor.Pool.Get(); try { existsAtPathVisitor.Path = new PropertyPath(path); TryAccept(existsAtPathVisitor, ref container); return existsAtPathVisitor.Exists; } finally { ExistsAtPathVisitor.Pool.Release(existsAtPathVisitor); } } public static bool IsPathValid(ref TContainer container, in PropertyPath path) { ExistsAtPathVisitor existsAtPathVisitor = ExistsAtPathVisitor.Pool.Get(); try { existsAtPathVisitor.Path = path; TryAccept(existsAtPathVisitor, ref container); return existsAtPathVisitor.Exists; } finally { ExistsAtPathVisitor.Pool.Release(existsAtPathVisitor); } } public static void SetValue(TContainer container, string name, TValue value) { SetValue(ref container, name, value); } public static void SetValue(ref TContainer container, string name, TValue value) { SetValue(ref container, new PropertyPath(name), value); } public static void SetValue(TContainer container, in PropertyPath path, TValue value) { SetValue(ref container, in path, value); } public static void SetValue(ref TContainer container, in PropertyPath path, TValue value) { if (path.Length == 0) { throw new ArgumentNullException("path"); } if (path.Length <= 0) { throw new InvalidPathException("The specified PropertyPath is empty."); } if (TrySetValue(ref container, in path, value, out var returnCode)) { return; } switch (returnCode) { case VisitReturnCode.NullContainer: throw new ArgumentNullException("container"); case VisitReturnCode.InvalidContainerType: throw new InvalidContainerTypeException(container.GetType()); case VisitReturnCode.MissingPropertyBag: throw new MissingPropertyBagException(container.GetType()); case VisitReturnCode.InvalidCast: throw new InvalidCastException($"Failed to SetValue of Type=[{typeof(TValue).Name}] for property with path=[{path}]"); case VisitReturnCode.InvalidPath: throw new InvalidPathException($"Failed to SetValue for property with Path=[{path}]"); case VisitReturnCode.AccessViolation: throw new AccessViolationException($"Failed to SetValue for read-only property with Path=[{path}]"); default: throw new Exception(string.Format("Unexpected {0}=[{1}]", "VisitReturnCode", returnCode)); } } public static bool TrySetValue(TContainer container, string name, TValue value) { return TrySetValue(ref container, name, value); } public static bool TrySetValue(ref TContainer container, string name, TValue value) { return TrySetValue(ref container, new PropertyPath(name), value); } public static bool TrySetValue(TContainer container, in PropertyPath path, TValue value) { return TrySetValue(ref container, in path, value); } public static bool TrySetValue(ref TContainer container, in PropertyPath path, TValue value) { VisitReturnCode returnCode; return TrySetValue(ref container, in path, value, out returnCode); } public static bool TrySetValue(ref TContainer container, in PropertyPath path, TValue value, out VisitReturnCode returnCode) { if (path.IsEmpty) { returnCode = VisitReturnCode.InvalidPath; return false; } SetValueVisitor setValueVisitor = SetValueVisitor.Pool.Get(); setValueVisitor.Path = path; setValueVisitor.Value = value; try { if (!TryAccept(setValueVisitor, ref container, out returnCode)) { return false; } returnCode = setValueVisitor.ReturnCode; } finally { SetValueVisitor.Pool.Release(setValueVisitor); } return returnCode == VisitReturnCode.Ok; } } public enum VisitReturnCode { Ok, NullContainer, InvalidContainerType, MissingPropertyBag, InvalidPath, InvalidCast, AccessViolation } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] public class GeneratePropertyBagsForAssemblyAttribute : Attribute { } [RequireAttributeUsages] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class CreatePropertyAttribute : RequiredMemberAttribute { public bool ReadOnly { get; set; } = false; } [AttributeUsage(AttributeTargets.Field)] public class DontCreatePropertyAttribute : Attribute { } [Flags] public enum TypeGenerationOptions { None = 0, ValueType = 2, ReferenceType = 4, Default = 6 } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class GeneratePropertyBagsForTypesQualifiedWithAttribute : Attribute { public Type Type { get; } public TypeGenerationOptions Options { get; } public GeneratePropertyBagsForTypesQualifiedWithAttribute(Type type, TypeGenerationOptions options = TypeGenerationOptions.Default) { if (type == null) { throw new ArgumentException("type is null."); } if (!type.IsInterface) { throw new ArgumentException("GeneratePropertyBagsForTypesQualifiedWithAttribute Type must be an interface type."); } Type = type; Options = options; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class GeneratePropertyBagsForTypeAttribute : Attribute { public Type Type { get; } public GeneratePropertyBagsForTypeAttribute(Type type) { if (!TypeTraits.IsContainer(type)) { throw new ArgumentException(type.Name + " is not a valid container type."); } Type = type; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] public class GeneratePropertyBagAttribute : Attribute { } [Serializable] public class MissingPropertyBagException : Exception { public Type Type { get; } public MissingPropertyBagException(Type type) : base(GetMessageForType(type)) { Type = type; } public MissingPropertyBagException(Type type, Exception inner) : base(GetMessageForType(type), inner) { Type = type; } private static string GetMessageForType(Type type) { return "No PropertyBag was found for Type=[" + type.FullName + "]. Please make sure all types are declared ahead of time using [GeneratePropertyBagAttribute], [GeneratePropertyBagsForTypeAttribute] or [GeneratePropertyBagsForTypesQualifiedWithAttribute]"; } } [Serializable] public class InvalidContainerTypeException : Exception { public Type Type { get; } public InvalidContainerTypeException(Type type) : base(GetMessageForType(type)) { Type = type; } public InvalidContainerTypeException(Type type, Exception inner) : base(GetMessageForType(type), inner) { Type = type; } private static string GetMessageForType(Type type) { return "Invalid container Type=[" + type.Name + "." + type.Name + "]"; } } [Serializable] public class InvalidPathException : Exception { public InvalidPathException(string message) : base(message) { } public InvalidPathException(string message, Exception inner) : base(message, inner) { } } public readonly struct AttributesScope : IDisposable { private readonly IAttributes m_Target; private readonly List m_Previous; public AttributesScope(IProperty target, IProperty source) { m_Target = target as IAttributes; m_Previous = (target as IAttributes)?.Attributes; if (m_Target != null) { m_Target.Attributes = (source as IAttributes)?.Attributes; } } internal AttributesScope(IAttributes target, List attributes) { m_Target = target; m_Previous = target.Attributes; target.Attributes = attributes; } public void Dispose() { if (m_Target != null) { m_Target.Attributes = m_Previous; } } } public delegate TValue PropertyGetter(ref TContainer container); public delegate void PropertySetter(ref TContainer container, TValue value); public class DelegateProperty : Property { private readonly PropertyGetter m_Getter; private readonly PropertySetter m_Setter; public override string Name { get; } public override bool IsReadOnly => m_Setter == null; public DelegateProperty(string name, PropertyGetter getter, PropertySetter setter = null) { Name = name; m_Getter = getter ?? throw new ArgumentException("getter"); m_Setter = setter; } public override TValue GetValue(ref TContainer container) { return m_Getter(ref container); } public override void SetValue(ref TContainer container, TValue value) { if (IsReadOnly) { throw new InvalidOperationException("Property is ReadOnly."); } m_Setter(ref container, value); } } public interface ICollectionElementProperty { } public interface IListElementProperty : ICollectionElementProperty { int Index { get; } } public interface ISetElementProperty : ICollectionElementProperty { object ObjectKey { get; } } public interface ISetElementProperty : ISetElementProperty, ICollectionElementProperty { TKey Key { get; } } public interface IDictionaryElementProperty : ICollectionElementProperty { object ObjectKey { get; } } public interface IDictionaryElementProperty : IDictionaryElementProperty, ICollectionElementProperty { TKey Key { get; } } public interface IProperty { string Name { get; } bool IsReadOnly { get; } Type DeclaredValueType(); bool HasAttribute() where TAttribute : Attribute; TAttribute GetAttribute() where TAttribute : Attribute; IEnumerable GetAttributes() where TAttribute : Attribute; IEnumerable GetAttributes(); } public interface IProperty : IProperty, IPropertyAccept { object GetValue(ref TContainer container); void SetValue(ref TContainer container, object value); } public abstract class Property : IProperty, IProperty, IPropertyAccept, IAttributes { private List m_Attributes; List IAttributes.Attributes { get { return m_Attributes; } set { m_Attributes = value; } } public abstract string Name { get; } public abstract bool IsReadOnly { get; } public Type DeclaredValueType() { return typeof(TValue); } public void Accept(IPropertyVisitor visitor, ref TContainer container) { visitor.Visit(this, ref container); } object IProperty.GetValue(ref TContainer container) { return GetValue(ref container); } void IProperty.SetValue(ref TContainer container, object value) { SetValue(ref container, TypeConversion.Convert(ref value)); } public abstract TValue GetValue(ref TContainer container); public abstract void SetValue(ref TContainer container, TValue value); protected void AddAttribute(Attribute attribute) { ((IAttributes)this).AddAttribute(attribute); } protected void AddAttributes(IEnumerable attributes) { ((IAttributes)this).AddAttributes(attributes); } void IAttributes.AddAttribute(Attribute attribute) { if (attribute != null && !(attribute.GetType() == typeof(CreatePropertyAttribute))) { if (m_Attributes == null) { m_Attributes = new List(); } m_Attributes.Add(attribute); } } void IAttributes.AddAttributes(IEnumerable attributes) { if (m_Attributes == null) { m_Attributes = new List(); } foreach (Attribute attribute in attributes) { if (attribute != null) { m_Attributes.Add(attribute); } } } public bool HasAttribute() where TAttribute : Attribute { for (int i = 0; i < m_Attributes?.Count; i++) { if (m_Attributes[i] is TAttribute) { return true; } } return false; } public TAttribute GetAttribute() where TAttribute : Attribute { for (int i = 0; i < m_Attributes?.Count; i++) { if (m_Attributes[i] is TAttribute result) { return result; } } return null; } public IEnumerable GetAttributes() where TAttribute : Attribute { for (int i = 0; i < m_Attributes?.Count; i++) { Attribute attribute = m_Attributes[i]; if (attribute is TAttribute typed) { yield return typed; } } } public IEnumerable GetAttributes() { for (int i = 0; i < m_Attributes?.Count; i++) { yield return m_Attributes[i]; } } AttributesScope IAttributes.CreateAttributesScope(IAttributes attributes) { return new AttributesScope(this, attributes?.Attributes); } } public enum PropertyPathPartKind { Name, Index, Key } public readonly struct PropertyPathPart : IEquatable { private readonly PropertyPathPartKind m_Kind; private readonly string m_Name; private readonly int m_Index; private readonly object m_Key; public bool IsName => Kind == PropertyPathPartKind.Name; public bool IsIndex => Kind == PropertyPathPartKind.Index; public bool IsKey => Kind == PropertyPathPartKind.Key; public PropertyPathPartKind Kind => m_Kind; public string Name { get { CheckKind(PropertyPathPartKind.Name); return m_Name; } } public int Index { get { CheckKind(PropertyPathPartKind.Index); return m_Index; } } public object Key { get { CheckKind(PropertyPathPartKind.Key); return m_Key; } } public PropertyPathPart(string name) { m_Kind = PropertyPathPartKind.Name; m_Name = name; m_Index = -1; m_Key = null; } public PropertyPathPart(int index) { m_Kind = PropertyPathPartKind.Index; m_Name = string.Empty; m_Index = index; m_Key = null; } public PropertyPathPart(object key) { m_Kind = PropertyPathPartKind.Key; m_Name = string.Empty; m_Index = -1; m_Key = key; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckKind(PropertyPathPartKind type) { if (type != Kind) { throw new InvalidOperationException(); } } public override string ToString() { PropertyPathPartKind kind = Kind; if (1 == 0) { } string result = kind switch { PropertyPathPartKind.Name => m_Name, PropertyPathPartKind.Index => "[" + m_Index + "]", PropertyPathPartKind.Key => "[\"" + m_Key?.ToString() + "\"]", _ => throw new ArgumentOutOfRangeException(), }; if (1 == 0) { } return result; } public bool Equals(PropertyPathPart other) { return m_Kind == other.m_Kind && m_Name == other.m_Name && m_Index == other.m_Index && object.Equals(m_Key, other.m_Key); } public override bool Equals(object obj) { return obj is PropertyPathPart other && Equals(other); } public override int GetHashCode() { int kind = (int)m_Kind; PropertyPathPartKind kind2 = m_Kind; if (1 == 0) { } int result = kind2 switch { PropertyPathPartKind.Name => (kind * 397) ^ ((m_Name != null) ? m_Name.GetHashCode() : 0), PropertyPathPartKind.Index => (kind * 397) ^ m_Index, PropertyPathPartKind.Key => (kind * 397) ^ ((m_Key != null) ? m_Key.GetHashCode() : 0), _ => throw new ArgumentOutOfRangeException(), }; if (1 == 0) { } return result; } } public readonly struct PropertyPath : IEquatable { internal const int k_InlineCount = 4; private readonly PropertyPathPart m_Part0; private readonly PropertyPathPart m_Part1; private readonly PropertyPathPart m_Part2; private readonly PropertyPathPart m_Part3; private readonly PropertyPathPart[] m_AdditionalParts; public int Length { get; } public bool IsEmpty => Length == 0; public PropertyPathPart this[int index] { get { switch (index) { case 0: if (Length < 1) { throw new IndexOutOfRangeException(); } return m_Part0; case 1: if (Length < 2) { throw new IndexOutOfRangeException(); } return m_Part1; case 2: if (Length < 3) { throw new IndexOutOfRangeException(); } return m_Part2; case 3: if (Length < 4) { throw new IndexOutOfRangeException(); } return m_Part3; default: return m_AdditionalParts[index - 4]; } } } public PropertyPath(string path) { PropertyPath propertyPath = ConstructFromPath(path); m_Part0 = propertyPath.m_Part0; m_Part1 = propertyPath.m_Part1; m_Part2 = propertyPath.m_Part2; m_Part3 = propertyPath.m_Part3; m_AdditionalParts = propertyPath.m_AdditionalParts; Length = propertyPath.Length; } private PropertyPath(in PropertyPathPart part) { m_Part0 = part; m_Part1 = default(PropertyPathPart); m_Part2 = default(PropertyPathPart); m_Part3 = default(PropertyPathPart); m_AdditionalParts = null; Length = 1; } private PropertyPath(in PropertyPathPart part0, in PropertyPathPart part1) { m_Part0 = part0; m_Part1 = part1; m_Part2 = default(PropertyPathPart); m_Part3 = default(PropertyPathPart); m_AdditionalParts = null; Length = 2; } private PropertyPath(in PropertyPathPart part0, in PropertyPathPart part1, in PropertyPathPart part2) { m_Part0 = part0; m_Part1 = part1; m_Part2 = part2; m_Part3 = default(PropertyPathPart); m_AdditionalParts = null; Length = 3; } private PropertyPath(in PropertyPathPart part0, in PropertyPathPart part1, in PropertyPathPart part2, in PropertyPathPart part3) { m_Part0 = part0; m_Part1 = part1; m_Part2 = part2; m_Part3 = part3; m_AdditionalParts = null; Length = 4; } internal PropertyPath(List parts) { m_Part0 = default(PropertyPathPart); m_Part1 = default(PropertyPathPart); m_Part2 = default(PropertyPathPart); m_Part3 = default(PropertyPathPart); m_AdditionalParts = ((parts.Count > 4) ? new PropertyPathPart[parts.Count - 4] : null); for (int i = 0; i < parts.Count; i++) { switch (i) { case 0: m_Part0 = parts[i]; break; case 1: m_Part1 = parts[i]; break; case 2: m_Part2 = parts[i]; break; case 3: m_Part3 = parts[i]; break; default: m_AdditionalParts[i - 4] = parts[i]; break; } } Length = parts.Count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath FromPart(in PropertyPathPart part) { return new PropertyPath(in part); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath FromName(string name) { return new PropertyPath(new PropertyPathPart(name)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath FromIndex(int index) { return new PropertyPath(new PropertyPathPart(index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath FromKey(object key) { return new PropertyPath(new PropertyPathPart(key)); } public static PropertyPath Combine(in PropertyPath path, in PropertyPath pathToAppend) { if (path.IsEmpty) { return pathToAppend; } if (pathToAppend.IsEmpty) { return path; } int length = path.Length; int length2 = pathToAppend.Length; int num = length + length2; if (num <= 4) { int index = 0; PropertyPathPart part = path.m_Part0; PropertyPathPart part2 = ((length > 1) ? path.m_Part1 : pathToAppend[index++]); PropertyPathPart part3 = ((num <= 2) ? default(PropertyPathPart) : ((length > 2) ? path.m_Part2 : pathToAppend[index++])); PropertyPathPart part4 = ((num <= 3) ? default(PropertyPathPart) : ((length > 3) ? path.m_Part3 : pathToAppend[index])); switch (num) { case 2: return new PropertyPath(in part, in part2); case 3: return new PropertyPath(in part, in part2, in part3); case 4: return new PropertyPath(in part, in part2, in part3, in part4); } } List list = CollectionPool, PropertyPathPart>.Get(); try { GetParts(in path, list); GetParts(in pathToAppend, list); return new PropertyPath(list); } finally { CollectionPool, PropertyPathPart>.Release(list); } } public static PropertyPath Combine(in PropertyPath path, string pathToAppend) { if (string.IsNullOrEmpty(pathToAppend)) { return path; } return Combine(in path, new PropertyPath(pathToAppend)); } public static PropertyPath AppendPart(in PropertyPath path, in PropertyPathPart part) { if (path.IsEmpty) { return new PropertyPath(in part); } switch (path.Length) { case 1: return new PropertyPath(in path.m_Part0, in part); case 2: return new PropertyPath(in path.m_Part0, in path.m_Part1, in part); case 3: return new PropertyPath(in path.m_Part0, in path.m_Part1, in path.m_Part2, in part); default: { List list = CollectionPool, PropertyPathPart>.Get(); try { GetParts(in path, list); list.Add(part); return new PropertyPath(list); } finally { CollectionPool, PropertyPathPart>.Release(list); } } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath AppendName(in PropertyPath path, string name) { return AppendPart(in path, new PropertyPathPart(name)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath AppendIndex(in PropertyPath path, int index) { return AppendPart(in path, new PropertyPathPart(index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath AppendKey(in PropertyPath path, object key) { return AppendPart(in path, new PropertyPathPart(key)); } public static PropertyPath AppendProperty(in PropertyPath path, IProperty property) { if (1 == 0) { } PropertyPath result = ((property is IListElementProperty listElementProperty) ? AppendPart(in path, new PropertyPathPart(listElementProperty.Index)) : ((property is ISetElementProperty setElementProperty) ? AppendPart(in path, new PropertyPathPart(setElementProperty.ObjectKey)) : ((!(property is IDictionaryElementProperty dictionaryElementProperty)) ? AppendPart(in path, new PropertyPathPart(property.Name)) : AppendPart(in path, new PropertyPathPart(dictionaryElementProperty.ObjectKey))))); if (1 == 0) { } return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath Pop(in PropertyPath path) { return SubPath(in path, 0, path.Length - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PropertyPath SubPath(in PropertyPath path, int startIndex) { return SubPath(in path, startIndex, path.Length - startIndex); } public static PropertyPath SubPath(in PropertyPath path, int startIndex, int length) { int length2 = path.Length; if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex"); } if (startIndex > length2) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0) { throw new ArgumentOutOfRangeException("length"); } if (startIndex > length2 - length) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return default(PropertyPath); } if (startIndex == 0 && length == length2) { return path; } switch (length) { case 1: return new PropertyPath(path[startIndex]); case 2: return new PropertyPath(path[startIndex], path[startIndex + 1]); case 3: return new PropertyPath(path[startIndex], path[startIndex + 1], path[startIndex + 2]); case 4: return new PropertyPath(path[startIndex], path[startIndex + 1], path[startIndex + 2], path[startIndex + 3]); default: { List list = CollectionPool, PropertyPathPart>.Get(); try { for (int i = startIndex; i < startIndex + length; i++) { list.Add(path[i]); } return new PropertyPath(list); } finally { CollectionPool, PropertyPathPart>.Release(list); } } } } public override string ToString() { if (Length == 0) { return string.Empty; } if (Length == 1 && m_Part0.IsName) { return m_Part0.Name; } StringBuilder stringBuilder = new StringBuilder(32); if (Length > 0) { AppendToBuilder(in m_Part0, stringBuilder); } if (Length > 1) { AppendToBuilder(in m_Part1, stringBuilder); } if (Length > 2) { AppendToBuilder(in m_Part2, stringBuilder); } if (Length > 3) { AppendToBuilder(in m_Part3, stringBuilder); } if (Length > 4) { PropertyPathPart[] additionalParts = m_AdditionalParts; for (int i = 0; i < additionalParts.Length; i++) { PropertyPathPart part = additionalParts[i]; AppendToBuilder(in part, stringBuilder); } } return stringBuilder.ToString(); } private static void AppendToBuilder(in PropertyPathPart part, StringBuilder builder) { switch (part.Kind) { case PropertyPathPartKind.Name: if (builder.Length > 0) { builder.Append('.'); } builder.Append(part.ToString()); break; case PropertyPathPartKind.Index: case PropertyPathPartKind.Key: builder.Append(part.ToString()); break; default: throw new ArgumentOutOfRangeException(); } } private static void GetParts(in PropertyPath path, List parts) { int length = path.Length; for (int i = 0; i < length; i++) { parts.Add(path[i]); } } private static PropertyPath ConstructFromPath(string path) { if (string.IsNullOrWhiteSpace(path)) { return default(PropertyPath); } int index = 0; int length = path.Length; int state = 0; List list = CollectionPool, PropertyPathPart>.Get(); try { list.Clear(); while (index < length) { switch (state) { case 0: TrimStart(); if (index == length) { break; } if (path[index] == '.') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } if (path[index] == '[') { state = 2; break; } if (path[index] == '"') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } state = 1; break; case 1: { int num3 = index; while (index < length && path[index] != '.' && path[index] != '[') { int num = index + 1; index = num; } if (num3 == index) { throw new ArgumentException("Invalid PropertyPath: Name is empty."); } if (index == length) { list.Add(new PropertyPathPart(path.Substring(num3))); state = 0; } else { list.Add(new PropertyPathPart(path.Substring(num3, index - num3))); ReadNext(); } break; } case 2: if (path[index] != '[') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } if (index + 1 < length && path[index + 1] == '"') { state = 4; } else { state = 3; } break; case 3: { if (path[index] != '[') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } int num = index + 1; index = num; int num4 = index; while (index < length) { char c2 = path[index]; if (c2 == ']') { break; } num = index + 1; index = num; } if (path[index] != ']') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } string s = path.Substring(num4, index - num4); if (!int.TryParse(s, out var result)) { throw new ArgumentException("Indices in PropertyPath must be a numeric value."); } if (result < 0) { throw new ArgumentException("Invalid PropertyPath: Negative indices are not supported."); } list.Add(new PropertyPathPart(result)); num = index + 1; index = num; if (index != length) { ReadNext(); } break; } case 4: { if (path[index] != '[') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } int num = index + 1; index = num; if (path[index] != '"') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } num = index + 1; index = num; int num2 = index; while (index < length) { char c = path[index]; if (c == '"') { break; } num = index + 1; index = num; } if (path[index] != '"') { throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } if (index + 1 < length && path[index + 1] == ']') { string key = path.Substring(num2, index - num2); list.Add(new PropertyPathPart((object)key)); index += 2; ReadNext(); break; } throw new ArgumentException("Invalid PropertyPath: No matching end quote for key."); } } } return new PropertyPath(list); } finally { CollectionPool, PropertyPathPart>.Release(list); } void ReadNext() { if (index == length) { state = 0; } else { switch (path[index]) { case '.': { int num5 = index + 1; index = num5; state = 0; break; } case '[': state = 2; break; default: throw new ArgumentException(string.Format("{0}: Invalid '{1}' character encountered at index '{2}'.", "PropertyPath", path[index], index)); } } } void TrimStart() { while (index < length && path[index] == ' ') { int num5 = index + 1; index = num5; } } } public static bool operator ==(PropertyPath lhs, PropertyPath rhs) { return lhs.Equals(rhs); } public static bool operator !=(PropertyPath lhs, PropertyPath rhs) { return !(lhs == rhs); } public bool Equals(PropertyPath other) { if (Length != other.Length) { return false; } for (int i = 0; i < Length; i++) { if (!this[i].Equals(other[i])) { return false; } } return true; } public override bool Equals(object obj) { if (obj is PropertyPath other) { return Equals(other); } return false; } public override int GetHashCode() { int num = 19; int length = Length; if (length == 0) { return num; } if (length > 0) { num = num * 31 + m_Part0.GetHashCode(); } if (length > 1) { num = num * 31 + m_Part1.GetHashCode(); } if (length > 2) { num = num * 31 + m_Part2.GetHashCode(); } if (length > 3) { num = num * 31 + m_Part3.GetHashCode(); } if (length <= 4) { return num; } PropertyPathPart[] additionalParts = m_AdditionalParts; for (int i = 0; i < additionalParts.Length; i++) { PropertyPathPart propertyPathPart = additionalParts[i]; num = num * 31 + propertyPathPart.GetHashCode(); } return num; } } internal interface IMemberInfo { string Name { get; } bool IsReadOnly { get; } Type ValueType { get; } object GetValue(object obj); void SetValue(object obj, object value); IEnumerable GetCustomAttributes(); } internal readonly struct FieldMember : IMemberInfo { internal readonly FieldInfo m_FieldInfo; public string Name { get; } public bool IsReadOnly => m_FieldInfo.IsInitOnly; public Type ValueType => m_FieldInfo.FieldType; public FieldMember(FieldInfo fieldInfo) { m_FieldInfo = fieldInfo; Name = ReflectionUtilities.SanitizeMemberName(m_FieldInfo); } public object GetValue(object obj) { return m_FieldInfo.GetValue(obj); } public void SetValue(object obj, object value) { m_FieldInfo.SetValue(obj, value); } public IEnumerable GetCustomAttributes() { return m_FieldInfo.GetCustomAttributes(); } } internal readonly struct PropertyMember : IMemberInfo { internal readonly PropertyInfo m_PropertyInfo; public string Name { get; } public bool IsReadOnly => !m_PropertyInfo.CanWrite; public Type ValueType => m_PropertyInfo.PropertyType; public PropertyMember(PropertyInfo propertyInfo) { m_PropertyInfo = propertyInfo; Name = ReflectionUtilities.SanitizeMemberName(m_PropertyInfo); } public object GetValue(object obj) { return m_PropertyInfo.GetValue(obj); } public void SetValue(object obj, object value) { m_PropertyInfo.SetValue(obj, value); } public IEnumerable GetCustomAttributes() { return m_PropertyInfo.GetCustomAttributes(); } } public class ReflectedMemberProperty : Property { private delegate TValue GetStructValueAction(ref TContainer container); private delegate void SetStructValueAction(ref TContainer container, TValue value); private delegate TValue GetClassValueAction(TContainer container); private delegate void SetClassValueAction(TContainer container, TValue value); private readonly IMemberInfo m_Info; private readonly bool m_IsStructContainerType; private GetStructValueAction m_GetStructValueAction; private SetStructValueAction m_SetStructValueAction; private GetClassValueAction m_GetClassValueAction; private SetClassValueAction m_SetClassValueAction; public override string Name { get; } public override bool IsReadOnly { get; } public ReflectedMemberProperty(FieldInfo info, string name) : this((IMemberInfo)new FieldMember(info), name) { } public ReflectedMemberProperty(PropertyInfo info, string name) : this((IMemberInfo)new PropertyMember(info), name) { } internal ReflectedMemberProperty(IMemberInfo info, string name) { Name = name; m_Info = info; m_IsStructContainerType = TypeTraits.IsValueType; AddAttributes(info.GetCustomAttributes()); bool flag = m_Info.IsReadOnly; if (base.HasAttribute()) { CreatePropertyAttribute attribute = base.GetAttribute(); flag |= attribute.ReadOnly; } IsReadOnly = flag; if (m_Info is FieldMember fieldMember) { FieldInfo fieldInfo = fieldMember.m_FieldInfo; DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, fieldInfo.FieldType, new Type[1] { m_IsStructContainerType ? fieldInfo.ReflectedType.MakeByRefType() : fieldInfo.ReflectedType }, restrictedSkipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); if (m_IsStructContainerType) { m_GetStructValueAction = (GetStructValueAction)dynamicMethod.CreateDelegate(typeof(GetStructValueAction)); } else { m_GetClassValueAction = (GetClassValueAction)dynamicMethod.CreateDelegate(typeof(GetClassValueAction)); } if (!flag) { dynamicMethod = new DynamicMethod(string.Empty, typeof(void), new Type[2] { m_IsStructContainerType ? fieldInfo.ReflectedType.MakeByRefType() : fieldInfo.ReflectedType, fieldInfo.FieldType }, restrictedSkipVisibility: true); iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Stfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); if (m_IsStructContainerType) { m_SetStructValueAction = (SetStructValueAction)dynamicMethod.CreateDelegate(typeof(SetStructValueAction)); } else { m_SetClassValueAction = (SetClassValueAction)dynamicMethod.CreateDelegate(typeof(SetClassValueAction)); } } } else { if (!(m_Info is PropertyMember propertyMember)) { return; } if (m_IsStructContainerType) { MethodInfo getMethod = propertyMember.m_PropertyInfo.GetGetMethod(nonPublic: true); m_GetStructValueAction = (GetStructValueAction)Delegate.CreateDelegate(typeof(GetStructValueAction), getMethod); if (!flag) { MethodInfo setMethod = propertyMember.m_PropertyInfo.GetSetMethod(nonPublic: true); m_SetStructValueAction = (SetStructValueAction)Delegate.CreateDelegate(typeof(SetStructValueAction), setMethod); } } else { MethodInfo getMethod2 = propertyMember.m_PropertyInfo.GetGetMethod(nonPublic: true); m_GetClassValueAction = (GetClassValueAction)Delegate.CreateDelegate(typeof(GetClassValueAction), getMethod2); if (!flag) { MethodInfo setMethod2 = propertyMember.m_PropertyInfo.GetSetMethod(nonPublic: true); m_SetClassValueAction = (SetClassValueAction)Delegate.CreateDelegate(typeof(SetClassValueAction), setMethod2); } } } } public override TValue GetValue(ref TContainer container) { if (m_IsStructContainerType) { return (m_GetStructValueAction == null) ? ((TValue)m_Info.GetValue(container)) : m_GetStructValueAction(ref container); } return (m_GetClassValueAction == null) ? ((TValue)m_Info.GetValue(container)) : m_GetClassValueAction(container); } public override void SetValue(ref TContainer container, TValue value) { if (IsReadOnly) { throw new InvalidOperationException("Property is ReadOnly."); } if (m_IsStructContainerType) { if (m_SetStructValueAction == null) { object obj = container; m_Info.SetValue(obj, value); container = (TContainer)obj; } else { m_SetStructValueAction(ref container, value); } } else if (m_SetClassValueAction == null) { m_Info.SetValue(container, value); } else { m_SetClassValueAction(container, value); } } } public sealed class ArrayPropertyBag : IndexedCollectionPropertyBag { protected override InstantiationKind InstantiationKind => InstantiationKind.PropertyBagOverride; protected override TElement[] InstantiateWithCount(int count) { return new TElement[count]; } protected override TElement[] Instantiate() { return Array.Empty(); } } public abstract class ContainerPropertyBag : PropertyBag, INamedProperties { private readonly List> m_PropertiesList = new List>(); private readonly Dictionary> m_PropertiesHash = new Dictionary>(); static ContainerPropertyBag() { if (!TypeTraits.IsContainer(typeof(TContainer))) { throw new InvalidOperationException($"Failed to create a property bag for Type=[{typeof(TContainer)}]. The type is not a valid container type."); } } protected void AddProperty(Property property) { m_PropertiesList.Add(property); m_PropertiesHash.Add(property.Name, property); } public override PropertyCollection GetProperties() { return new PropertyCollection(m_PropertiesList); } public override PropertyCollection GetProperties(ref TContainer container) { return new PropertyCollection(m_PropertiesList); } public bool TryGetProperty(ref TContainer container, string name, out IProperty property) { return m_PropertiesHash.TryGetValue(name, out property); } } public class DictionaryPropertyBag : KeyValueCollectionPropertyBag, TKey, TValue> { protected override InstantiationKind InstantiationKind => InstantiationKind.PropertyBagOverride; protected override Dictionary Instantiate() { return new Dictionary(); } } public class HashSetPropertyBag : SetPropertyBagBase, TElement> { protected override InstantiationKind InstantiationKind => InstantiationKind.PropertyBagOverride; protected override HashSet Instantiate() { return new HashSet(); } } internal readonly struct IndexedCollectionPropertyBagEnumerable { private readonly IIndexedCollectionPropertyBagEnumerator m_Impl; private readonly TContainer m_Container; public IndexedCollectionPropertyBagEnumerable(IIndexedCollectionPropertyBagEnumerator impl, TContainer container) { m_Impl = impl; m_Container = container; } public IndexedCollectionPropertyBagEnumerator GetEnumerator() { return new IndexedCollectionPropertyBagEnumerator(m_Impl, m_Container); } } internal struct IndexedCollectionPropertyBagEnumerator : IEnumerator>, IEnumerator, IDisposable { private readonly IIndexedCollectionPropertyBagEnumerator m_Impl; private readonly IndexedCollectionSharedPropertyState m_Previous; private TContainer m_Container; private int m_Position; public IProperty Current => m_Impl.GetSharedProperty(); object IEnumerator.Current => Current; internal IndexedCollectionPropertyBagEnumerator(IIndexedCollectionPropertyBagEnumerator impl, TContainer container) { m_Impl = impl; m_Container = container; m_Previous = impl.GetSharedPropertyState(); m_Position = -1; } public bool MoveNext() { m_Position++; if (m_Position < m_Impl.GetCount(ref m_Container)) { m_Impl.SetSharedPropertyState(new IndexedCollectionSharedPropertyState { Index = m_Position, IsReadOnly = false }); return true; } m_Impl.SetSharedPropertyState(m_Previous); return false; } public void Reset() { m_Position = -1; m_Impl.SetSharedPropertyState(m_Previous); } public void Dispose() { } } internal interface IIndexedCollectionPropertyBagEnumerator { int GetCount(ref TContainer container); IProperty GetSharedProperty(); IndexedCollectionSharedPropertyState GetSharedPropertyState(); void SetSharedPropertyState(IndexedCollectionSharedPropertyState state); } internal struct IndexedCollectionSharedPropertyState { public int Index; public bool IsReadOnly; } public class IndexedCollectionPropertyBag : PropertyBag, IListPropertyBag, ICollectionPropertyBag, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, IListPropertyBagAccept, IListPropertyAccept, IIndexedProperties, IConstructorWithCount, IConstructor, IIndexedCollectionPropertyBagEnumerator where TList : IList { private class ListElementProperty : Property, IListElementProperty, ICollectionElementProperty { internal int m_Index; internal bool m_IsReadOnly; public int Index => m_Index; public override string Name => Index.ToString(); public override bool IsReadOnly => m_IsReadOnly; public override TElement GetValue(ref TList container) { int index = m_Index; return container[index]; } public override void SetValue(ref TList container, TElement value) { int index = m_Index; container[index] = value; } } private readonly ListElementProperty m_Property = new ListElementProperty(); public override PropertyCollection GetProperties() { return PropertyCollection.Empty; } public override PropertyCollection GetProperties(ref TList container) { return new PropertyCollection(new IndexedCollectionPropertyBagEnumerable(this, container)); } public bool TryGetProperty(ref TList container, int index, out IProperty property) { if ((uint)index >= (uint)container.Count) { property = null; return false; } property = new ListElementProperty { m_Index = index, m_IsReadOnly = false }; return true; } void ICollectionPropertyBagAccept.Accept(ICollectionPropertyBagVisitor visitor, ref TList container) { visitor.Visit(this, ref container); } void IListPropertyBagAccept.Accept(IListPropertyBagVisitor visitor, ref TList list) { visitor.Visit(this, ref list); } void IListPropertyAccept.Accept(IListPropertyVisitor visitor, Property property, ref TContainer container, ref TList list) { using (new AttributesScope(m_Property, property)) { visitor.Visit(property, ref container, ref list); } } TList IConstructorWithCount.InstantiateWithCount(int count) { return InstantiateWithCount(count); } protected virtual TList InstantiateWithCount(int count) { return default(TList); } int IIndexedCollectionPropertyBagEnumerator.GetCount(ref TList container) { return container.Count; } IProperty IIndexedCollectionPropertyBagEnumerator.GetSharedProperty() { return m_Property; } IndexedCollectionSharedPropertyState IIndexedCollectionPropertyBagEnumerator.GetSharedPropertyState() { return new IndexedCollectionSharedPropertyState { Index = m_Property.m_Index, IsReadOnly = m_Property.IsReadOnly }; } void IIndexedCollectionPropertyBagEnumerator.SetSharedPropertyState(IndexedCollectionSharedPropertyState state) { m_Property.m_Index = state.Index; m_Property.m_IsReadOnly = state.IsReadOnly; } } public interface IIndexedProperties { bool TryGetProperty(ref TContainer container, int index, out IProperty property); } public interface INamedProperties { bool TryGetProperty(ref TContainer container, string name, out IProperty property); } public interface IKeyedProperties { bool TryGetProperty(ref TContainer container, TKey key, out IProperty property); } public interface IPropertyBag { void Accept(ITypeVisitor visitor); void Accept(IPropertyBagVisitor visitor, ref object container); } public interface IPropertyBag : IPropertyBag { PropertyCollection GetProperties(); PropertyCollection GetProperties(ref TContainer container); TContainer CreateInstance(); bool TryCreateInstance(out TContainer instance); void Accept(IPropertyBagVisitor visitor, ref TContainer container); } public interface ICollectionPropertyBag : IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept where TCollection : ICollection { } public interface IListPropertyBag : ICollectionPropertyBag, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, IListPropertyBagAccept, IListPropertyAccept, IIndexedProperties where TList : IList { } public interface ISetPropertyBag : ICollectionPropertyBag, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, ISetPropertyBagAccept, ISetPropertyAccept, IKeyedProperties where TSet : ISet { } public interface IDictionaryPropertyBag : ICollectionPropertyBag>, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, IDictionaryPropertyBagAccept, IDictionaryPropertyAccept, IKeyedProperties where TDictionary : IDictionary { } public class KeyValueCollectionPropertyBag : PropertyBag, IDictionaryPropertyBag, ICollectionPropertyBag>, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, IDictionaryPropertyBagAccept, IDictionaryPropertyAccept, IKeyedProperties where TDictionary : IDictionary { private class KeyValuePairProperty : Property>, IDictionaryElementProperty, IDictionaryElementProperty, ICollectionElementProperty { public override string Name => Key.ToString(); public override bool IsReadOnly => false; public TKey Key { get; internal set; } public object ObjectKey => Key; public override KeyValuePair GetValue(ref TDictionary container) { TKey key = Key; TKey key2 = Key; return new KeyValuePair(key, container[key2]); } public override void SetValue(ref TDictionary container, KeyValuePair value) { TKey key = value.Key; TValue value2 = value.Value; container[key] = value2; } } private readonly struct Enumerable : IEnumerable>, IEnumerable { private class Enumerator : IEnumerator>, IEnumerator, IDisposable { private readonly TDictionary m_Dictionary; private readonly KeyValuePairProperty m_Property; private readonly TKey m_Previous; private readonly List m_Keys; private int m_Position; public IProperty Current => m_Property; object IEnumerator.Current => Current; public Enumerator(TDictionary dictionary, KeyValuePairProperty property) { m_Dictionary = dictionary; m_Property = property; m_Previous = property.Key; m_Position = -1; m_Keys = CollectionPool, TKey>.Get(); m_Keys.AddRange(m_Dictionary.Keys); } public bool MoveNext() { m_Position++; if (m_Position < m_Dictionary.Count) { m_Property.Key = m_Keys[m_Position]; return true; } m_Property.Key = m_Previous; return false; } public void Reset() { m_Position = -1; m_Property.Key = m_Previous; } public void Dispose() { CollectionPool, TKey>.Release(m_Keys); } } private readonly TDictionary m_Dictionary; private readonly KeyValuePairProperty m_Property; public Enumerable(TDictionary dictionary, KeyValuePairProperty property) { m_Dictionary = dictionary; m_Property = property; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(m_Dictionary, m_Property); } IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(m_Dictionary, m_Property); } } private readonly KeyValuePairProperty m_KeyValuePairProperty = new KeyValuePairProperty(); public override PropertyCollection GetProperties() { return PropertyCollection.Empty; } public override PropertyCollection GetProperties(ref TDictionary container) { return new PropertyCollection(new Enumerable(container, m_KeyValuePairProperty)); } void ICollectionPropertyBagAccept.Accept(ICollectionPropertyBagVisitor visitor, ref TDictionary container) { visitor.Visit(this, ref container); } void IDictionaryPropertyBagAccept.Accept(IDictionaryPropertyBagVisitor visitor, ref TDictionary container) { visitor.Visit(this, ref container); } void IDictionaryPropertyAccept.Accept(IDictionaryPropertyVisitor visitor, Property property, ref TContainer container, ref TDictionary dictionary) { using (new AttributesScope(m_KeyValuePairProperty, property)) { visitor.Visit(property, ref container, ref dictionary); } } bool IKeyedProperties.TryGetProperty(ref TDictionary container, object key, out IProperty property) { TKey key2 = (TKey)key; if (container.ContainsKey(key2)) { property = new KeyValuePairProperty { Key = (TKey)key }; return true; } property = null; return false; } } public class KeyValuePairPropertyBag : PropertyBag>, INamedProperties> { private static readonly DelegateProperty, TKey> s_KeyProperty = new DelegateProperty, TKey>("Key", delegate(ref KeyValuePair container) { return container.Key; }); private static readonly DelegateProperty, TValue> s_ValueProperty = new DelegateProperty, TValue>("Value", delegate(ref KeyValuePair container) { return container.Value; }); public override PropertyCollection> GetProperties() { return new PropertyCollection>(GetPropertiesEnumerable()); } public override PropertyCollection> GetProperties(ref KeyValuePair container) { return new PropertyCollection>(GetPropertiesEnumerable()); } private static IEnumerable>> GetPropertiesEnumerable() { yield return s_KeyProperty; yield return s_ValueProperty; } public bool TryGetProperty(ref KeyValuePair container, string name, out IProperty> property) { if (name == "Key") { property = s_KeyProperty; return true; } if (name == "Value") { property = s_ValueProperty; return true; } property = null; return false; } } public class ListPropertyBag : IndexedCollectionPropertyBag, TElement> { protected override InstantiationKind InstantiationKind => InstantiationKind.PropertyBagOverride; protected override List InstantiateWithCount(int count) { return new List(count); } protected override List Instantiate() { return new List(); } } public static class PropertyBag { public static void AcceptWithSpecializedVisitor(IPropertyBag properties, IPropertyBagVisitor visitor, ref TContainer container) { if (properties == null) { throw new ArgumentNullException("properties"); } if (!(properties is IDictionaryPropertyBagAccept dictionaryPropertyBagAccept) || !(visitor is IDictionaryPropertyBagVisitor visitor2)) { if (!(properties is IListPropertyBagAccept listPropertyBagAccept) || !(visitor is IListPropertyBagVisitor visitor3)) { if (!(properties is ISetPropertyBagAccept setPropertyBagAccept) || !(visitor is ISetPropertyBagVisitor visitor4)) { if (properties is ICollectionPropertyBagAccept collectionPropertyBagAccept && visitor is ICollectionPropertyBagVisitor visitor5) { collectionPropertyBagAccept.Accept(visitor5, ref container); } else { properties.Accept(visitor, ref container); } } else { setPropertyBagAccept.Accept(visitor4, ref container); } } else { listPropertyBagAccept.Accept(visitor3, ref container); } } else { dictionaryPropertyBagAccept.Accept(visitor2, ref container); } } public static void Register(PropertyBag propertyBag) { PropertyBagStore.AddPropertyBag(propertyBag); } public static void RegisterArray() { if (PropertyBagStore.TypedStore>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new ArrayPropertyBag()); } } public static void RegisterArray() { RegisterArray(); } public static void RegisterList() { if (PropertyBagStore.TypedStore>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new ListPropertyBag()); } } public static void RegisterList() { RegisterList(); } public static void RegisterHashSet() { if (PropertyBagStore.TypedStore>>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new HashSetPropertyBag()); } } public static void RegisterHashSet() { RegisterHashSet(); } public static void RegisterDictionary() { if (PropertyBagStore.TypedStore>>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new DictionaryPropertyBag()); } } public static void RegisterDictionary() { RegisterDictionary(); } public static void RegisterIList() where TList : IList { if (PropertyBagStore.TypedStore>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new IndexedCollectionPropertyBag()); } } public static void RegisterIList() where TList : IList { RegisterIList(); } public static void RegisterISet() where TSet : ISet { if (PropertyBagStore.TypedStore>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new SetPropertyBagBase()); } } public static void RegisterISet() where TSet : ISet { RegisterISet(); } public static void RegisterIDictionary() where TDictionary : IDictionary { if (PropertyBagStore.TypedStore>.PropertyBag == null) { PropertyBagStore.AddPropertyBag(new KeyValueCollectionPropertyBag()); PropertyBagStore.AddPropertyBag(new KeyValuePairPropertyBag()); } } public static void RegisterIDictionary() where TDictionary : IDictionary { RegisterIDictionary(); } public static TContainer CreateInstance() { IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(); if (propertyBag == null) { throw new MissingPropertyBagException(typeof(TContainer)); } return propertyBag.CreateInstance(); } public static IPropertyBag GetPropertyBag(Type type) { return PropertyBagStore.GetPropertyBag(type); } public static IPropertyBag GetPropertyBag() { return PropertyBagStore.GetPropertyBag(); } public static bool TryGetPropertyBagForValue(ref TValue value, out IPropertyBag propertyBag) { return PropertyBagStore.TryGetPropertyBagForValue(ref value, out propertyBag); } public static bool Exists() { return PropertyBagStore.Exists(); } public static bool Exists(Type type) { return PropertyBagStore.Exists(type); } public static IEnumerable GetAllTypesWithAPropertyBag() { return PropertyBagStore.AllTypes; } } public abstract class PropertyBag : IPropertyBag, IPropertyBag, IPropertyBagRegister, IConstructor, IConstructor { InstantiationKind IConstructor.InstantiationKind => InstantiationKind; protected virtual InstantiationKind InstantiationKind { get; } = InstantiationKind.Activator; static PropertyBag() { if (!TypeTraits.IsContainer(typeof(TContainer))) { throw new InvalidOperationException($"Failed to create a property bag for Type=[{typeof(TContainer)}]. The type is not a valid container type."); } } void IPropertyBagRegister.Register() { PropertyBagStore.AddPropertyBag(this); } public void Accept(ITypeVisitor visitor) { if (visitor == null) { throw new ArgumentNullException("visitor"); } visitor.Visit(); } void IPropertyBag.Accept(IPropertyBagVisitor visitor, ref object container) { if (container == null) { throw new ArgumentNullException("container"); } if (!(container is TContainer container2) || 1 == 0) { throw new ArgumentException($"The given ContainerType=[{container.GetType()}] does not match the PropertyBagType=[{typeof(TContainer)}]"); } PropertyBag.AcceptWithSpecializedVisitor(this, visitor, ref container2); container = container2; } void IPropertyBag.Accept(IPropertyBagVisitor visitor, ref TContainer container) { visitor.Visit(this, ref container); } PropertyCollection IPropertyBag.GetProperties() { return GetProperties(); } PropertyCollection IPropertyBag.GetProperties(ref TContainer container) { return GetProperties(ref container); } TContainer IConstructor.Instantiate() { return Instantiate(); } public abstract PropertyCollection GetProperties(); public abstract PropertyCollection GetProperties(ref TContainer container); protected virtual TContainer Instantiate() { return default(TContainer); } public TContainer CreateInstance() { return TypeUtility.Instantiate(); } public bool TryCreateInstance(out TContainer instance) { return TypeUtility.TryInstantiate(out instance); } } public readonly struct PropertyCollection : IEnumerable>, IEnumerable { private enum EnumeratorType { Empty, Enumerable, List, IndexedCollectionPropertyBag } public struct Enumerator : IEnumerator>, IEnumerator, IDisposable { private readonly EnumeratorType m_Type; private IEnumerator> m_Enumerator; private List>.Enumerator m_Properties; private IndexedCollectionPropertyBagEnumerator m_IndexedCollectionPropertyBag; public IProperty Current { get; private set; } object IEnumerator.Current => Current; internal Enumerator(IEnumerator> enumerator) { m_Type = EnumeratorType.Enumerable; m_Enumerator = enumerator; m_Properties = default(List>.Enumerator); m_IndexedCollectionPropertyBag = default(IndexedCollectionPropertyBagEnumerator); Current = null; } internal Enumerator(List>.Enumerator properties) { m_Type = EnumeratorType.List; m_Enumerator = null; m_Properties = properties; m_IndexedCollectionPropertyBag = default(IndexedCollectionPropertyBagEnumerator); Current = null; } internal Enumerator(IndexedCollectionPropertyBagEnumerator enumerator) { m_Type = EnumeratorType.IndexedCollectionPropertyBag; m_Enumerator = null; m_Properties = default(List>.Enumerator); m_IndexedCollectionPropertyBag = enumerator; Current = null; } public bool MoveNext() { bool result; switch (m_Type) { case EnumeratorType.Empty: return false; case EnumeratorType.Enumerable: result = m_Enumerator.MoveNext(); Current = m_Enumerator.Current; break; case EnumeratorType.List: result = m_Properties.MoveNext(); Current = m_Properties.Current; break; case EnumeratorType.IndexedCollectionPropertyBag: result = m_IndexedCollectionPropertyBag.MoveNext(); Current = m_IndexedCollectionPropertyBag.Current; break; default: throw new ArgumentOutOfRangeException(); } return result; } public void Reset() { switch (m_Type) { case EnumeratorType.Empty: break; case EnumeratorType.Enumerable: m_Enumerator.Reset(); break; case EnumeratorType.List: ((IEnumerator)m_Properties).Reset(); break; case EnumeratorType.IndexedCollectionPropertyBag: m_IndexedCollectionPropertyBag.Reset(); break; default: throw new ArgumentOutOfRangeException(); } } public void Dispose() { switch (m_Type) { case EnumeratorType.Empty: break; case EnumeratorType.Enumerable: m_Enumerator.Dispose(); break; case EnumeratorType.List: break; case EnumeratorType.IndexedCollectionPropertyBag: m_IndexedCollectionPropertyBag.Dispose(); break; default: throw new ArgumentOutOfRangeException(); } } } private readonly EnumeratorType m_Type; private readonly IEnumerable> m_Enumerable; private readonly List> m_Properties; private readonly IndexedCollectionPropertyBagEnumerable m_IndexedCollectionPropertyBag; public static PropertyCollection Empty { get; } = default(PropertyCollection); public PropertyCollection(IEnumerable> enumerable) { m_Type = EnumeratorType.Enumerable; m_Enumerable = enumerable; m_Properties = null; m_IndexedCollectionPropertyBag = default(IndexedCollectionPropertyBagEnumerable); } public PropertyCollection(List> properties) { m_Type = EnumeratorType.List; m_Enumerable = null; m_Properties = properties; m_IndexedCollectionPropertyBag = default(IndexedCollectionPropertyBagEnumerable); } internal PropertyCollection(IndexedCollectionPropertyBagEnumerable enumerable) { m_Type = EnumeratorType.IndexedCollectionPropertyBag; m_Enumerable = null; m_Properties = null; m_IndexedCollectionPropertyBag = enumerable; } public Enumerator GetEnumerator() { return m_Type switch { EnumeratorType.Empty => default(Enumerator), EnumeratorType.Enumerable => new Enumerator(m_Enumerable.GetEnumerator()), EnumeratorType.List => new Enumerator(m_Properties.GetEnumerator()), EnumeratorType.IndexedCollectionPropertyBag => new Enumerator(m_IndexedCollectionPropertyBag.GetEnumerator()), _ => throw new ArgumentOutOfRangeException(), }; } IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class SetPropertyBagBase : PropertyBag, ISetPropertyBag, ICollectionPropertyBag, IPropertyBag, IPropertyBag, ICollectionPropertyBagAccept, ISetPropertyBagAccept, ISetPropertyAccept, IKeyedProperties where TSet : ISet { private class SetElementProperty : Property, ISetElementProperty, ISetElementProperty, ICollectionElementProperty { internal TElement m_Value; public override string Name => m_Value.ToString(); public override bool IsReadOnly => true; public TElement Key => m_Value; public object ObjectKey => m_Value; public override TElement GetValue(ref TSet container) { return m_Value; } public override void SetValue(ref TSet container, TElement value) { throw new InvalidOperationException("Property is ReadOnly."); } } private readonly SetElementProperty m_Property = new SetElementProperty(); public override PropertyCollection GetProperties() { return PropertyCollection.Empty; } public override PropertyCollection GetProperties(ref TSet container) { return new PropertyCollection(GetPropertiesEnumerable(container)); } private IEnumerable> GetPropertiesEnumerable(TSet container) { foreach (TElement element in container) { m_Property.m_Value = element; yield return m_Property; } } void ICollectionPropertyBagAccept.Accept(ICollectionPropertyBagVisitor visitor, ref TSet container) { visitor.Visit(this, ref container); } void ISetPropertyBagAccept.Accept(ISetPropertyBagVisitor visitor, ref TSet container) { visitor.Visit(this, ref container); } void ISetPropertyAccept.Accept(ISetPropertyVisitor visitor, Property property, ref TContainer container, ref TSet dictionary) { using (new AttributesScope(m_Property, property)) { visitor.Visit(property, ref container, ref dictionary); } } public bool TryGetProperty(ref TSet container, object key, out IProperty property) { TElement item = (TElement)key; if (container.Contains(item)) { property = new SetElementProperty { m_Value = (TElement)key }; return true; } property = null; return false; } } public interface IExcludePropertyAdapter : IPropertyVisitorAdapter { bool IsExcluded(in ExcludeContext context, ref TContainer container, ref TValue value); } public interface IExcludePropertyAdapter : IPropertyVisitorAdapter { bool IsExcluded(in ExcludeContext context, ref TContainer container, ref TValue value); } public interface IExcludePropertyAdapter : IPropertyVisitorAdapter { bool IsExcluded(in ExcludeContext context, ref TContainer container, ref TValue value); } public interface IExcludeContravariantPropertyAdapter : IPropertyVisitorAdapter { bool IsExcluded(in ExcludeContext context, ref TContainer container, TValue value); } public interface IExcludeContravariantPropertyAdapter : IPropertyVisitorAdapter { bool IsExcluded(in ExcludeContext context, ref TContainer container, TValue value); } public interface IVisitPrimitivesPropertyAdapter : IVisitPropertyAdapter, IPropertyVisitorAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter, IVisitPropertyAdapter { } public interface IVisitPropertyAdapter : IPropertyVisitorAdapter { void Visit(in VisitContext context, ref TContainer container, ref TValue value); } public interface IVisitPropertyAdapter : IPropertyVisitorAdapter { void Visit(in VisitContext context, ref TContainer container, ref TValue value); } public interface IVisitPropertyAdapter : IPropertyVisitorAdapter { void Visit(in VisitContext context, ref TContainer container, ref TValue value); } public interface IVisitContravariantPropertyAdapter : IPropertyVisitorAdapter { void Visit(in VisitContext context, ref TContainer container, TValue value); } public interface IVisitContravariantPropertyAdapter : IPropertyVisitorAdapter { void Visit(in VisitContext context, ref TContainer container, TValue value); } public abstract class ConcreteTypeVisitor : IPropertyBagVisitor { protected abstract void VisitContainer(ref TContainer container); void IPropertyBagVisitor.Visit(IPropertyBag properties, ref TContainer container) { VisitContainer(ref container); } } public readonly struct ExcludeContext { private readonly PropertyVisitor m_Visitor; public Property Property { get; } internal static ExcludeContext FromProperty(PropertyVisitor visitor, Property property) { return new ExcludeContext(visitor, property); } private ExcludeContext(PropertyVisitor visitor, Property property) { m_Visitor = visitor; Property = property; } } public readonly struct ExcludeContext { private readonly PropertyVisitor m_Visitor; public IProperty Property { get; } internal static ExcludeContext FromProperty(PropertyVisitor visitor, Property property) { return new ExcludeContext(visitor, property); } private ExcludeContext(PropertyVisitor visitor, IProperty property) { m_Visitor = visitor; Property = property; } } public interface ICollectionPropertyBagAccept { void Accept(ICollectionPropertyBagVisitor visitor, ref TContainer container); } public interface IListPropertyBagAccept { void Accept(IListPropertyBagVisitor visitor, ref TContainer container); } public interface ISetPropertyBagAccept { void Accept(ISetPropertyBagVisitor visitor, ref TContainer container); } public interface IDictionaryPropertyBagAccept { void Accept(IDictionaryPropertyBagVisitor visitor, ref TContainer container); } public interface IPropertyAccept { void Accept(IPropertyVisitor visitor, ref TContainer container); } public interface ICollectionPropertyAccept { void Accept(ICollectionPropertyVisitor visitor, Property property, ref TContainer container, ref TCollection collection); } public interface IListPropertyAccept { void Accept(IListPropertyVisitor visitor, Property property, ref TContainer container, ref TList list); } public interface ISetPropertyAccept { void Accept(ISetPropertyVisitor visitor, Property property, ref TContainer container, ref TSet set); } public interface IDictionaryPropertyAccept { void Accept(IDictionaryPropertyVisitor visitor, Property property, ref TContainer container, ref TDictionary dictionary); } public interface ITypeVisitor { void Visit(); } public interface IPropertyBagVisitor { void Visit(IPropertyBag properties, ref TContainer container); } public interface ICollectionPropertyBagVisitor { void Visit(ICollectionPropertyBag properties, ref TCollection container) where TCollection : ICollection; } public interface IListPropertyBagVisitor { void Visit(IListPropertyBag properties, ref TList container) where TList : IList; } public interface ISetPropertyBagVisitor { void Visit(ISetPropertyBag properties, ref TSet container) where TSet : ISet; } public interface IDictionaryPropertyBagVisitor { void Visit(IDictionaryPropertyBag properties, ref TDictionary container) where TDictionary : IDictionary; } public interface IPropertyVisitor { void Visit(Property property, ref TContainer container); } public interface ICollectionPropertyVisitor { void Visit(Property property, ref TContainer container, ref TCollection collection) where TCollection : ICollection; } public interface IListPropertyVisitor { void Visit(Property property, ref TContainer container, ref TList list) where TList : IList; } public interface ISetPropertyVisitor { void Visit(Property property, ref TContainer container, ref TSet set) where TSet : ISet; } public interface IDictionaryPropertyVisitor { void Visit(Property property, ref TContainer container, ref TDictionary dictionary) where TDictionary : IDictionary; } public abstract class PathVisitor : IPropertyBagVisitor, IPropertyVisitor { private readonly struct PropertyScope : IDisposable { private readonly PathVisitor m_Visitor; private readonly IProperty m_Property; public PropertyScope(PathVisitor visitor, IProperty property) { m_Visitor = visitor; m_Property = m_Visitor.Property; m_Visitor.Property = property; } public void Dispose() { m_Visitor.Property = m_Property; } } private int m_PathIndex; public PropertyPath Path { get; set; } private IProperty Property { get; set; } public bool ReadonlyVisit { get; set; } public VisitReturnCode ReturnCode { get; protected set; } public virtual void Reset() { m_PathIndex = 0; Path = default(PropertyPath); ReturnCode = VisitReturnCode.Ok; ReadonlyVisit = false; } void IPropertyBagVisitor.Visit(IPropertyBag properties, ref TContainer container) { PropertyPathPart propertyPathPart = Path[m_PathIndex++]; IProperty property; switch (propertyPathPart.Kind) { case PropertyPathPartKind.Name: if (properties is INamedProperties namedProperties && namedProperties.TryGetProperty(ref container, propertyPathPart.Name, out property)) { property.Accept(this, ref container); } else { ReturnCode = VisitReturnCode.InvalidPath; } break; case PropertyPathPartKind.Index: if (properties is IIndexedProperties indexedProperties && indexedProperties.TryGetProperty(ref container, propertyPathPart.Index, out property)) { using ((property as IAttributes).CreateAttributesScope(Property as IAttributes)) { property.Accept(this, ref container); break; } } ReturnCode = VisitReturnCode.InvalidPath; break; case PropertyPathPartKind.Key: if (properties is IKeyedProperties keyedProperties && keyedProperties.TryGetProperty(ref container, propertyPathPart.Key, out property)) { using ((property as IAttributes).CreateAttributesScope(Property as IAttributes)) { property.Accept(this, ref container); break; } } ReturnCode = VisitReturnCode.InvalidPath; break; default: ReturnCode = VisitReturnCode.InvalidPath; break; } } void IPropertyVisitor.Visit(Property property, ref TContainer container) { TValue value = property.GetValue(ref container); IPropertyBag propertyBag; if (m_PathIndex >= Path.Length) { VisitPath(property, ref container, ref value); } else if (PropertyBag.TryGetPropertyBagForValue(ref value, out propertyBag)) { if (TypeTraits.CanBeNull && EqualityComparer.Default.Equals(value, default(TValue))) { ReturnCode = VisitReturnCode.InvalidPath; return; } using (new PropertyScope(this, property)) { PropertyContainer.Accept(this, ref value); } if (!property.IsReadOnly && !ReadonlyVisit) { property.SetValue(ref container, value); } } else { ReturnCode = VisitReturnCode.InvalidPath; } } protected virtual void VisitPath(Property property, ref TContainer container, ref TValue value) { } } public interface IPropertyVisitorAdapter { } public abstract class PropertyVisitor : IPropertyBagVisitor, IListPropertyBagVisitor, IDictionaryPropertyBagVisitor, IPropertyVisitor, ICollectionPropertyVisitor, IListPropertyVisitor, ISetPropertyVisitor, IDictionaryPropertyVisitor { private readonly List m_Adapters = new List(); public void AddAdapter(IPropertyVisitorAdapter adapter) { m_Adapters.Add(adapter); } public void RemoveAdapter(IPropertyVisitorAdapter adapter) { m_Adapters.Remove(adapter); } void IPropertyBagVisitor.Visit(IPropertyBag properties, ref TContainer container) { foreach (IProperty property in properties.GetProperties(ref container)) { property.Accept(this, ref container); } } void IListPropertyBagVisitor.Visit(IListPropertyBag properties, ref TList container) { foreach (IProperty property in properties.GetProperties(ref container)) { property.Accept(this, ref container); } } void IDictionaryPropertyBagVisitor.Visit(IDictionaryPropertyBag properties, ref TDictionary container) { foreach (IProperty property in properties.GetProperties(ref container)) { property.Accept(this, ref container); } } void IPropertyVisitor.Visit(Property property, ref TContainer container) { TValue value = property.GetValue(ref container); if (!IsExcluded(property, new ReadOnlyAdapterCollection(m_Adapters).GetEnumerator(), ref container, ref value) && !IsExcluded(property, ref container, ref value)) { ContinueVisitation(property, new ReadOnlyAdapterCollection(m_Adapters).GetEnumerator(), ref container, ref value); if (!property.IsReadOnly) { property.SetValue(ref container, value); } } } internal void ContinueVisitation(Property property, ref TContainer container, ref TValue value) { if (PropertyBagStore.TryGetPropertyBagForValue(ref value, out var propertyBag)) { IPropertyBag propertyBag2 = propertyBag; IPropertyBag propertyBag3 = propertyBag2; if (propertyBag3 is IDictionaryPropertyAccept dictionaryPropertyAccept) { dictionaryPropertyAccept.Accept(this, property, ref container, ref value); return; } if (propertyBag3 is IListPropertyAccept listPropertyAccept) { listPropertyAccept.Accept(this, property, ref container, ref value); return; } if (propertyBag3 is ISetPropertyAccept setPropertyAccept) { setPropertyAccept.Accept(this, property, ref container, ref value); return; } if (propertyBag3 is ICollectionPropertyAccept collectionPropertyAccept) { collectionPropertyAccept.Accept(this, property, ref container, ref value); return; } } VisitProperty(property, ref container, ref value); } void ICollectionPropertyVisitor.Visit(Property property, ref TContainer container, ref TCollection collection) { VisitCollection(property, ref container, ref collection); } void IListPropertyVisitor.Visit(Property property, ref TContainer container, ref TList list) { VisitList(property, ref container, ref list); } void ISetPropertyVisitor.Visit(Property property, ref TContainer container, ref TSet set) { VisitSet(property, ref container, ref set); } void IDictionaryPropertyVisitor.Visit(Property property, ref TContainer container, ref TDictionary dictionary) { VisitDictionary(property, ref container, ref dictionary); } protected virtual bool IsExcluded(Property property, ref TContainer container, ref TValue value) { return false; } protected virtual void VisitProperty(Property property, ref TContainer container, ref TValue value) { PropertyContainer.TryAccept(this, ref value); } protected virtual void VisitCollection(Property property, ref TContainer container, ref TCollection value) where TCollection : ICollection { VisitProperty(property, ref container, ref value); } protected virtual void VisitList(Property property, ref TContainer container, ref TList value) where TList : IList { VisitCollection(property, ref container, ref value); } protected virtual void VisitSet(Property property, ref TContainer container, ref TSet value) where TSet : ISet { VisitCollection(property, ref container, ref value); } protected virtual void VisitDictionary(Property property, ref TContainer container, ref TDictionary value) where TDictionary : IDictionary { VisitCollection>(property, ref container, ref value); } private bool IsExcluded(Property property, ReadOnlyAdapterCollection.Enumerator enumerator, ref TContainer container, ref TValue value) { while (enumerator.MoveNext()) { IPropertyVisitorAdapter current = enumerator.Current; IPropertyVisitorAdapter propertyVisitorAdapter = current; IPropertyVisitorAdapter propertyVisitorAdapter2 = propertyVisitorAdapter; if (!(propertyVisitorAdapter2 is IExcludePropertyAdapter excludePropertyAdapter)) { if (!(propertyVisitorAdapter2 is IExcludeContravariantPropertyAdapter excludeContravariantPropertyAdapter)) { if (!(propertyVisitorAdapter2 is IExcludePropertyAdapter excludePropertyAdapter2)) { if (!(propertyVisitorAdapter2 is IExcludeContravariantPropertyAdapter excludeContravariantPropertyAdapter2)) { if (!(propertyVisitorAdapter2 is IExcludePropertyAdapter excludePropertyAdapter3) || !excludePropertyAdapter3.IsExcluded(ExcludeContext.FromProperty(this, property), ref container, ref value)) { continue; } return true; } bool flag = excludeContravariantPropertyAdapter2.IsExcluded(ExcludeContext.FromProperty(this, property), ref container, value); value = property.GetValue(ref container); if (flag) { return true; } } else if (excludePropertyAdapter2.IsExcluded(ExcludeContext.FromProperty(this, property), ref container, ref value)) { return true; } } else { bool flag2 = excludeContravariantPropertyAdapter.IsExcluded(ExcludeContext.FromProperty(this, property), ref container, value); value = property.GetValue(ref container); if (flag2) { return true; } } } else if (excludePropertyAdapter.IsExcluded(ExcludeContext.FromProperty(this, property), ref container, ref value)) { return true; } } return false; } internal void ContinueVisitation(Property property, ReadOnlyAdapterCollection.Enumerator enumerator, ref TContainer container, ref TValue value) { while (enumerator.MoveNext()) { IPropertyVisitorAdapter current = enumerator.Current; IPropertyVisitorAdapter propertyVisitorAdapter = current; IPropertyVisitorAdapter propertyVisitorAdapter2 = propertyVisitorAdapter; if (!(propertyVisitorAdapter2 is IVisitPropertyAdapter visitPropertyAdapter)) { if (!(propertyVisitorAdapter2 is IVisitContravariantPropertyAdapter visitContravariantPropertyAdapter)) { if (!(propertyVisitorAdapter2 is IVisitPropertyAdapter visitPropertyAdapter2)) { if (!(propertyVisitorAdapter2 is IVisitContravariantPropertyAdapter visitContravariantPropertyAdapter2)) { if (!(propertyVisitorAdapter2 is IVisitPropertyAdapter visitPropertyAdapter3)) { continue; } visitPropertyAdapter3.Visit(VisitContext.FromProperty(this, enumerator, property), ref container, ref value); return; } visitContravariantPropertyAdapter2.Visit(VisitContext.FromProperty(this, enumerator, property), ref container, value); value = property.GetValue(ref container); return; } visitPropertyAdapter2.Visit(VisitContext.FromProperty(this, enumerator, property), ref container, ref value); return; } visitContravariantPropertyAdapter.Visit(VisitContext.FromProperty(this, enumerator, property), ref container, value); value = property.GetValue(ref container); return; } visitPropertyAdapter.Visit(VisitContext.FromProperty(this, enumerator, property), ref container, ref value); return; } ContinueVisitationWithoutAdapters(property, enumerator, ref container, ref value); } internal void ContinueVisitationWithoutAdapters(Property property, ReadOnlyAdapterCollection.Enumerator enumerator, ref TContainer container, ref TValue value) { ContinueVisitation(property, ref container, ref value); } } public readonly struct VisitContext { private readonly ReadOnlyAdapterCollection.Enumerator m_Enumerator; private readonly PropertyVisitor m_Visitor; public Property Property { get; } internal static VisitContext FromProperty(PropertyVisitor visitor, ReadOnlyAdapterCollection.Enumerator enumerator, Property property) { return new VisitContext(visitor, enumerator, property); } private VisitContext(PropertyVisitor visitor, ReadOnlyAdapterCollection.Enumerator enumerator, Property property) { m_Visitor = visitor; m_Enumerator = enumerator; Property = property; } public void ContinueVisitation(ref TContainer container, ref TValue value) { m_Visitor.ContinueVisitation(Property, m_Enumerator, ref container, ref value); } public void ContinueVisitationWithoutAdapters(ref TContainer container, ref TValue value) { m_Visitor.ContinueVisitationWithoutAdapters(Property, m_Enumerator, ref container, ref value); } } public readonly struct VisitContext { private delegate void VisitDelegate(PropertyVisitor visitor, ReadOnlyAdapterCollection.Enumerator enumerator, IProperty property, ref TContainer container); private delegate void VisitWithoutAdaptersDelegate(PropertyVisitor visitor, IProperty property, ref TContainer container); private readonly ReadOnlyAdapterCollection.Enumerator m_Enumerator; private readonly PropertyVisitor m_Visitor; private readonly VisitDelegate m_Continue; private readonly VisitWithoutAdaptersDelegate m_ContinueWithoutAdapters; public IProperty Property { get; } internal static VisitContext FromProperty(PropertyVisitor visitor, ReadOnlyAdapterCollection.Enumerator enumerator, Property property) { return new VisitContext(visitor, enumerator, property, delegate(PropertyVisitor v, ReadOnlyAdapterCollection.Enumerator e, IProperty p, ref TContainer c) { Property property2 = (Property)p; TValue value = property2.GetValue(ref c); v.ContinueVisitation(property2, e, ref c, ref value); }, delegate(PropertyVisitor v, IProperty p, ref TContainer c) { Property property2 = (Property)p; TValue value = property2.GetValue(ref c); v.ContinueVisitation(property2, ref c, ref value); }); } private VisitContext(PropertyVisitor visitor, ReadOnlyAdapterCollection.Enumerator enumerator, IProperty property, VisitDelegate continueVisitation, VisitWithoutAdaptersDelegate continueVisitationWithoutAdapters) { m_Visitor = visitor; m_Enumerator = enumerator; Property = property; m_Continue = continueVisitation; m_ContinueWithoutAdapters = continueVisitationWithoutAdapters; } public void ContinueVisitation(ref TContainer container) { m_Continue(m_Visitor, m_Enumerator, Property, ref container); } public void ContinueVisitationWithoutAdapters(ref TContainer container) { m_ContinueWithoutAdapters(m_Visitor, Property, ref container); } } [VisibleToOtherModules(new string[] { "UnityEngine.UIElementsModule" })] internal readonly struct ConversionRegistry : IEqualityComparer { private class ConverterKeyComparer : IEqualityComparer { public bool Equals(ConverterKey x, ConverterKey y) { return x.SourceType == y.SourceType && x.DestinationType == y.DestinationType; } public int GetHashCode(ConverterKey obj) { return (((obj.SourceType != null) ? obj.SourceType.GetHashCode() : 0) * 397) ^ ((obj.DestinationType != null) ? obj.DestinationType.GetHashCode() : 0); } } private readonly struct ConverterKey { public readonly Type SourceType; public readonly Type DestinationType; public ConverterKey(Type source, Type destination) { SourceType = source; DestinationType = destination; } } private static readonly ConverterKeyComparer Comparer = new ConverterKeyComparer(); private readonly Dictionary m_Converters; private ConversionRegistry(Dictionary storage) { m_Converters = storage; } public static ConversionRegistry Create() { return new ConversionRegistry(new Dictionary(Comparer)); } public void Register(Type source, Type destination, Delegate converter) { m_Converters[new ConverterKey(source, destination)] = converter ?? throw new ArgumentException("converter"); } public Delegate GetConverter(Type source, Type destination) { ConverterKey key = new ConverterKey(source, destination); Delegate value; return m_Converters.TryGetValue(key, out value) ? value : null; } public bool TryGetConverter(Type source, Type destination, out Delegate converter) { converter = GetConverter(source, destination); return (object)converter != null; } public bool Equals(ConversionRegistry x, ConversionRegistry y) { return x.m_Converters == y.m_Converters; } public int GetHashCode(ConversionRegistry obj) { return (obj.m_Converters != null) ? obj.m_Converters.GetHashCode() : 0; } } public delegate TDestination TypeConverter(ref TSource value); public static class TypeConversion { private static class PrimitiveConverters { public static void Register() { RegisterInt8Converters(); RegisterInt16Converters(); RegisterInt32Converters(); RegisterInt64Converters(); RegisterUInt8Converters(); RegisterUInt16Converters(); RegisterUInt32Converters(); RegisterUInt64Converters(); RegisterFloat32Converters(); RegisterFloat64Converters(); RegisterBooleanConverters(); RegisterCharConverters(); RegisterStringConverters(); RegisterObjectConverters(); s_GlobalConverters.Register(typeof(string), typeof(Guid), (TypeConverter)delegate(ref string g) { return new Guid(g); }); } private static void RegisterInt8Converters() { s_GlobalConverters.Register(typeof(sbyte), typeof(char), (TypeConverter)delegate(ref sbyte v) { return (char)v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(bool), (TypeConverter)delegate(ref sbyte v) { return v != 0; }); s_GlobalConverters.Register(typeof(sbyte), typeof(short), (TypeConverter)delegate(ref sbyte v) { return v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(int), (TypeConverter)delegate(ref sbyte v) { return v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(long), (TypeConverter)delegate(ref sbyte v) { return v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(byte), (TypeConverter)delegate(ref sbyte v) { return (byte)v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(ushort), (TypeConverter)delegate(ref sbyte v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(uint), (TypeConverter)delegate(ref sbyte v) { return (uint)v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(ulong), (TypeConverter)delegate(ref sbyte v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(float), (TypeConverter)delegate(ref sbyte v) { return v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(double), (TypeConverter)delegate(ref sbyte v) { return v; }); s_GlobalConverters.Register(typeof(sbyte), typeof(object), (TypeConverter)delegate(ref sbyte v) { return v; }); } private static void RegisterInt16Converters() { s_GlobalConverters.Register(typeof(short), typeof(sbyte), (TypeConverter)delegate(ref short v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(short), typeof(char), (TypeConverter)delegate(ref short v) { return (char)v; }); s_GlobalConverters.Register(typeof(short), typeof(bool), (TypeConverter)delegate(ref short v) { return v != 0; }); s_GlobalConverters.Register(typeof(short), typeof(int), (TypeConverter)delegate(ref short v) { return v; }); s_GlobalConverters.Register(typeof(short), typeof(long), (TypeConverter)delegate(ref short v) { return v; }); s_GlobalConverters.Register(typeof(short), typeof(byte), (TypeConverter)delegate(ref short v) { return (byte)v; }); s_GlobalConverters.Register(typeof(short), typeof(ushort), (TypeConverter)delegate(ref short v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(short), typeof(uint), (TypeConverter)delegate(ref short v) { return (uint)v; }); s_GlobalConverters.Register(typeof(short), typeof(ulong), (TypeConverter)delegate(ref short v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(short), typeof(float), (TypeConverter)delegate(ref short v) { return v; }); s_GlobalConverters.Register(typeof(short), typeof(double), (TypeConverter)delegate(ref short v) { return v; }); s_GlobalConverters.Register(typeof(short), typeof(object), (TypeConverter)delegate(ref short v) { return v; }); } private static void RegisterInt32Converters() { s_GlobalConverters.Register(typeof(int), typeof(sbyte), (TypeConverter)delegate(ref int v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(int), typeof(char), (TypeConverter)delegate(ref int v) { return (char)v; }); s_GlobalConverters.Register(typeof(int), typeof(bool), (TypeConverter)delegate(ref int v) { return v != 0; }); s_GlobalConverters.Register(typeof(int), typeof(short), (TypeConverter)delegate(ref int v) { return (short)v; }); s_GlobalConverters.Register(typeof(int), typeof(long), (TypeConverter)delegate(ref int v) { return v; }); s_GlobalConverters.Register(typeof(int), typeof(byte), (TypeConverter)delegate(ref int v) { return (byte)v; }); s_GlobalConverters.Register(typeof(int), typeof(ushort), (TypeConverter)delegate(ref int v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(int), typeof(uint), (TypeConverter)delegate(ref int v) { return (uint)v; }); s_GlobalConverters.Register(typeof(int), typeof(ulong), (TypeConverter)delegate(ref int v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(int), typeof(float), (TypeConverter)delegate(ref int v) { return v; }); s_GlobalConverters.Register(typeof(int), typeof(double), (TypeConverter)delegate(ref int v) { return v; }); s_GlobalConverters.Register(typeof(int), typeof(object), (TypeConverter)delegate(ref int v) { return v; }); } private static void RegisterInt64Converters() { s_GlobalConverters.Register(typeof(long), typeof(sbyte), (TypeConverter)delegate(ref long v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(long), typeof(char), (TypeConverter)delegate(ref long v) { return (char)v; }); s_GlobalConverters.Register(typeof(long), typeof(bool), (TypeConverter)delegate(ref long v) { return v != 0; }); s_GlobalConverters.Register(typeof(long), typeof(short), (TypeConverter)delegate(ref long v) { return (short)v; }); s_GlobalConverters.Register(typeof(long), typeof(int), (TypeConverter)delegate(ref long v) { return (int)v; }); s_GlobalConverters.Register(typeof(long), typeof(byte), (TypeConverter)delegate(ref long v) { return (byte)v; }); s_GlobalConverters.Register(typeof(long), typeof(ushort), (TypeConverter)delegate(ref long v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(long), typeof(uint), (TypeConverter)delegate(ref long v) { return (uint)v; }); s_GlobalConverters.Register(typeof(long), typeof(ulong), (TypeConverter)delegate(ref long v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(long), typeof(float), (TypeConverter)delegate(ref long v) { return v; }); s_GlobalConverters.Register(typeof(long), typeof(double), (TypeConverter)delegate(ref long v) { return v; }); s_GlobalConverters.Register(typeof(long), typeof(object), (TypeConverter)delegate(ref long v) { return v; }); } private static void RegisterUInt8Converters() { s_GlobalConverters.Register(typeof(byte), typeof(sbyte), (TypeConverter)delegate(ref byte v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(byte), typeof(char), (TypeConverter)delegate(ref byte v) { return (char)v; }); s_GlobalConverters.Register(typeof(byte), typeof(bool), (TypeConverter)delegate(ref byte v) { return v != 0; }); s_GlobalConverters.Register(typeof(byte), typeof(short), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(int), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(long), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(ushort), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(uint), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(ulong), (TypeConverter)delegate(ref byte v) { return v; }); s_GlobalConverters.Register(typeof(byte), typeof(float), (TypeConverter)delegate(ref byte v) { return (int)v; }); s_GlobalConverters.Register(typeof(byte), typeof(double), (TypeConverter)delegate(ref byte v) { return (int)v; }); s_GlobalConverters.Register(typeof(byte), typeof(object), (TypeConverter)delegate(ref byte v) { return v; }); } private static void RegisterUInt16Converters() { s_GlobalConverters.Register(typeof(ushort), typeof(sbyte), (TypeConverter)delegate(ref ushort v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(char), (TypeConverter)delegate(ref ushort v) { return (char)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(bool), (TypeConverter)delegate(ref ushort v) { return v != 0; }); s_GlobalConverters.Register(typeof(ushort), typeof(short), (TypeConverter)delegate(ref ushort v) { return (short)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(int), (TypeConverter)delegate(ref ushort v) { return v; }); s_GlobalConverters.Register(typeof(ushort), typeof(long), (TypeConverter)delegate(ref ushort v) { return v; }); s_GlobalConverters.Register(typeof(ushort), typeof(byte), (TypeConverter)delegate(ref ushort v) { return (byte)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(uint), (TypeConverter)delegate(ref ushort v) { return v; }); s_GlobalConverters.Register(typeof(ushort), typeof(ulong), (TypeConverter)delegate(ref ushort v) { return v; }); s_GlobalConverters.Register(typeof(ushort), typeof(float), (TypeConverter)delegate(ref ushort v) { return (int)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(double), (TypeConverter)delegate(ref ushort v) { return (int)v; }); s_GlobalConverters.Register(typeof(ushort), typeof(object), (TypeConverter)delegate(ref ushort v) { return v; }); } private static void RegisterUInt32Converters() { s_GlobalConverters.Register(typeof(uint), typeof(sbyte), (TypeConverter)delegate(ref uint v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(uint), typeof(char), (TypeConverter)delegate(ref uint v) { return (char)v; }); s_GlobalConverters.Register(typeof(uint), typeof(bool), (TypeConverter)delegate(ref uint v) { return v != 0; }); s_GlobalConverters.Register(typeof(uint), typeof(short), (TypeConverter)delegate(ref uint v) { return (short)v; }); s_GlobalConverters.Register(typeof(uint), typeof(int), (TypeConverter)delegate(ref uint v) { return (int)v; }); s_GlobalConverters.Register(typeof(uint), typeof(long), (TypeConverter)delegate(ref uint v) { return v; }); s_GlobalConverters.Register(typeof(uint), typeof(byte), (TypeConverter)delegate(ref uint v) { return (byte)v; }); s_GlobalConverters.Register(typeof(uint), typeof(ushort), (TypeConverter)delegate(ref uint v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(uint), typeof(ulong), (TypeConverter)delegate(ref uint v) { return v; }); s_GlobalConverters.Register(typeof(uint), typeof(float), (TypeConverter)delegate(ref uint v) { return v; }); s_GlobalConverters.Register(typeof(uint), typeof(double), (TypeConverter)delegate(ref uint v) { return v; }); s_GlobalConverters.Register(typeof(uint), typeof(object), (TypeConverter)delegate(ref uint v) { return v; }); } private static void RegisterUInt64Converters() { s_GlobalConverters.Register(typeof(ulong), typeof(sbyte), (TypeConverter)delegate(ref ulong v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(char), (TypeConverter)delegate(ref ulong v) { return (char)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(bool), (TypeConverter)delegate(ref ulong v) { return v != 0; }); s_GlobalConverters.Register(typeof(ulong), typeof(short), (TypeConverter)delegate(ref ulong v) { return (short)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(int), (TypeConverter)delegate(ref ulong v) { return (int)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(long), (TypeConverter)delegate(ref ulong v) { return (long)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(byte), (TypeConverter)delegate(ref ulong v) { return (byte)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(ushort), (TypeConverter)delegate(ref ulong v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(uint), (TypeConverter)delegate(ref ulong v) { return (uint)v; }); s_GlobalConverters.Register(typeof(ulong), typeof(float), (TypeConverter)delegate(ref ulong v) { return v; }); s_GlobalConverters.Register(typeof(ulong), typeof(double), (TypeConverter)delegate(ref ulong v) { return v; }); s_GlobalConverters.Register(typeof(ulong), typeof(object), (TypeConverter)delegate(ref ulong v) { return v; }); } private static void RegisterFloat32Converters() { s_GlobalConverters.Register(typeof(float), typeof(sbyte), (TypeConverter)delegate(ref float v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(float), typeof(char), (TypeConverter)delegate(ref float v) { return (char)v; }); s_GlobalConverters.Register(typeof(float), typeof(bool), (TypeConverter)delegate(ref float v) { return Math.Abs(v) > float.Epsilon; }); s_GlobalConverters.Register(typeof(float), typeof(short), (TypeConverter)delegate(ref float v) { return (short)v; }); s_GlobalConverters.Register(typeof(float), typeof(int), (TypeConverter)delegate(ref float v) { return (int)v; }); s_GlobalConverters.Register(typeof(float), typeof(long), (TypeConverter)delegate(ref float v) { return (long)v; }); s_GlobalConverters.Register(typeof(float), typeof(byte), (TypeConverter)delegate(ref float v) { return (byte)v; }); s_GlobalConverters.Register(typeof(float), typeof(ushort), (TypeConverter)delegate(ref float v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(float), typeof(uint), (TypeConverter)delegate(ref float v) { return (uint)v; }); s_GlobalConverters.Register(typeof(float), typeof(ulong), (TypeConverter)delegate(ref float v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(float), typeof(double), (TypeConverter)delegate(ref float v) { return v; }); s_GlobalConverters.Register(typeof(float), typeof(object), (TypeConverter)delegate(ref float v) { return v; }); } private static void RegisterFloat64Converters() { s_GlobalConverters.Register(typeof(double), typeof(sbyte), (TypeConverter)delegate(ref double v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(double), typeof(char), (TypeConverter)delegate(ref double v) { return (char)v; }); s_GlobalConverters.Register(typeof(double), typeof(bool), (TypeConverter)delegate(ref double v) { return Math.Abs(v) > double.Epsilon; }); s_GlobalConverters.Register(typeof(double), typeof(short), (TypeConverter)delegate(ref double v) { return (short)v; }); s_GlobalConverters.Register(typeof(double), typeof(int), (TypeConverter)delegate(ref double v) { return (int)v; }); s_GlobalConverters.Register(typeof(double), typeof(long), (TypeConverter)delegate(ref double v) { return (long)v; }); s_GlobalConverters.Register(typeof(double), typeof(byte), (TypeConverter)delegate(ref double v) { return (byte)v; }); s_GlobalConverters.Register(typeof(double), typeof(ushort), (TypeConverter)delegate(ref double v) { return (ushort)v; }); s_GlobalConverters.Register(typeof(double), typeof(uint), (TypeConverter)delegate(ref double v) { return (uint)v; }); s_GlobalConverters.Register(typeof(double), typeof(ulong), (TypeConverter)delegate(ref double v) { return (ulong)v; }); s_GlobalConverters.Register(typeof(double), typeof(float), (TypeConverter)delegate(ref double v) { return (float)v; }); s_GlobalConverters.Register(typeof(double), typeof(object), (TypeConverter)delegate(ref double v) { return v; }); } private static void RegisterBooleanConverters() { s_GlobalConverters.Register(typeof(bool), typeof(char), (TypeConverter)delegate(ref bool v) { return v ? '\u0001' : '\0'; }); s_GlobalConverters.Register(typeof(bool), typeof(sbyte), (TypeConverter)delegate(ref bool v) { return (sbyte)(v ? 1 : 0); }); s_GlobalConverters.Register(typeof(bool), typeof(short), (TypeConverter)delegate(ref bool v) { return (short)(v ? 1 : 0); }); s_GlobalConverters.Register(typeof(bool), typeof(int), (TypeConverter)delegate(ref bool v) { return v ? 1 : 0; }); s_GlobalConverters.Register(typeof(bool), typeof(long), (TypeConverter)delegate(ref bool v) { return v ? 1 : 0; }); s_GlobalConverters.Register(typeof(bool), typeof(byte), (TypeConverter)delegate(ref bool v) { return (byte)(v ? 1 : 0); }); s_GlobalConverters.Register(typeof(bool), typeof(ushort), (TypeConverter)delegate(ref bool v) { return (ushort)(v ? 1 : 0); }); s_GlobalConverters.Register(typeof(bool), typeof(uint), (TypeConverter)delegate(ref bool v) { return v ? 1u : 0u; }); s_GlobalConverters.Register(typeof(bool), typeof(ulong), (TypeConverter)delegate(ref bool v) { return (ulong)(v ? 1 : 0); }); s_GlobalConverters.Register(typeof(bool), typeof(float), (TypeConverter)delegate(ref bool v) { return v ? 1f : 0f; }); s_GlobalConverters.Register(typeof(bool), typeof(double), (TypeConverter)delegate(ref bool v) { return v ? 1.0 : 0.0; }); s_GlobalConverters.Register(typeof(bool), typeof(object), (TypeConverter)delegate(ref bool v) { return v; }); } private static void RegisterCharConverters() { s_GlobalConverters.Register(typeof(string), typeof(char), (TypeConverter)delegate(ref string v) { if (v.Length != 1) { throw new Exception("Not a valid char"); } return v[0]; }); s_GlobalConverters.Register(typeof(char), typeof(bool), (TypeConverter)delegate(ref char v) { return v != '\0'; }); s_GlobalConverters.Register(typeof(char), typeof(sbyte), (TypeConverter)delegate(ref char v) { return (sbyte)v; }); s_GlobalConverters.Register(typeof(char), typeof(short), (TypeConverter)delegate(ref char v) { return (short)v; }); s_GlobalConverters.Register(typeof(char), typeof(int), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(long), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(byte), (TypeConverter)delegate(ref char v) { return (byte)v; }); s_GlobalConverters.Register(typeof(char), typeof(ushort), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(uint), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(ulong), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(float), (TypeConverter)delegate(ref char v) { return (int)v; }); s_GlobalConverters.Register(typeof(char), typeof(double), (TypeConverter)delegate(ref char v) { return (int)v; }); s_GlobalConverters.Register(typeof(char), typeof(object), (TypeConverter)delegate(ref char v) { return v; }); s_GlobalConverters.Register(typeof(char), typeof(string), (TypeConverter)delegate(ref char v) { return v.ToString(); }); } private static void RegisterStringConverters() { s_GlobalConverters.Register(typeof(string), typeof(char), (TypeConverter)delegate(ref string v) { return (!string.IsNullOrEmpty(v)) ? v[0] : '\0'; }); s_GlobalConverters.Register(typeof(char), typeof(string), (TypeConverter)delegate(ref char v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(bool), (TypeConverter)delegate(ref string v) { bool result; double result2; return bool.TryParse(v, out result) ? result : (double.TryParse(v, out result2) && Convert(ref result2)); }); s_GlobalConverters.Register(typeof(bool), typeof(string), (TypeConverter)delegate(ref bool v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(sbyte), (TypeConverter)delegate(ref string v) { sbyte result; double result2; return (sbyte)(sbyte.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0)); }); s_GlobalConverters.Register(typeof(sbyte), typeof(string), (TypeConverter)delegate(ref sbyte v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(short), (TypeConverter)delegate(ref string v) { short result; double result2; return (short)(short.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0)); }); s_GlobalConverters.Register(typeof(short), typeof(string), (TypeConverter)delegate(ref short v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(int), (TypeConverter)delegate(ref string v) { int result; double result2; return int.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0); }); s_GlobalConverters.Register(typeof(int), typeof(string), (TypeConverter)delegate(ref int v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(long), (TypeConverter)delegate(ref string v) { long result; double result2; return long.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0); }); s_GlobalConverters.Register(typeof(long), typeof(string), (TypeConverter)delegate(ref long v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(byte), (TypeConverter)delegate(ref string v) { byte result; double result2; return (byte)(byte.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0)); }); s_GlobalConverters.Register(typeof(byte), typeof(string), (TypeConverter)delegate(ref byte v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(ushort), (TypeConverter)delegate(ref string v) { ushort result; double result2; return (ushort)(ushort.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0)); }); s_GlobalConverters.Register(typeof(ushort), typeof(string), (TypeConverter)delegate(ref ushort v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(uint), (TypeConverter)delegate(ref string v) { uint result; double result2; return uint.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0u); }); s_GlobalConverters.Register(typeof(uint), typeof(string), (TypeConverter)delegate(ref uint v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(ulong), (TypeConverter)delegate(ref string v) { ulong result; double result2; return ulong.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0); }); s_GlobalConverters.Register(typeof(ulong), typeof(string), (TypeConverter)delegate(ref ulong v) { return v.ToString(); }); s_GlobalConverters.Register(typeof(string), typeof(float), (TypeConverter)delegate(ref string v) { float result; double result2; return float.TryParse(v, out result) ? result : (double.TryParse(v, out result2) ? Convert(ref result2) : 0f); }); s_GlobalConverters.Register(typeof(float), typeof(string), (TypeConverter)delegate(ref float v) { return v.ToString(CultureInfo.InvariantCulture); }); s_GlobalConverters.Register(typeof(string), typeof(double), (TypeConverter)delegate(ref string v) { double.TryParse(v, out var result); return result; }); s_GlobalConverters.Register(typeof(double), typeof(string), (TypeConverter)delegate(ref double v) { return v.ToString(CultureInfo.InvariantCulture); }); } private static void RegisterObjectConverters() { s_GlobalConverters.Register(typeof(object), typeof(char), (TypeConverter)delegate(ref object v) { return (v is char c) ? c : '\0'; }); s_GlobalConverters.Register(typeof(object), typeof(bool), (TypeConverter)delegate(ref object v) { return v is bool flag && flag; }); s_GlobalConverters.Register(typeof(object), typeof(sbyte), (TypeConverter)delegate(ref object v) { return (sbyte)((v is sbyte b) ? b : 0); }); s_GlobalConverters.Register(typeof(object), typeof(short), (TypeConverter)delegate(ref object v) { return (short)((v is short num) ? num : 0); }); s_GlobalConverters.Register(typeof(object), typeof(int), (TypeConverter)delegate(ref object v) { return (v is int num) ? num : 0; }); s_GlobalConverters.Register(typeof(object), typeof(long), (TypeConverter)delegate(ref object v) { return (v is long num) ? num : 0; }); s_GlobalConverters.Register(typeof(object), typeof(byte), (TypeConverter)delegate(ref object v) { return (byte)((v is byte b) ? b : 0); }); s_GlobalConverters.Register(typeof(object), typeof(ushort), (TypeConverter)delegate(ref object v) { return (ushort)((v is ushort num) ? num : 0); }); s_GlobalConverters.Register(typeof(object), typeof(uint), (TypeConverter)delegate(ref object v) { return (v is uint num) ? num : 0u; }); s_GlobalConverters.Register(typeof(object), typeof(ulong), (TypeConverter)delegate(ref object v) { return (v is ulong num) ? num : 0; }); s_GlobalConverters.Register(typeof(object), typeof(float), (TypeConverter)delegate(ref object v) { return (v is float num) ? num : 0f; }); s_GlobalConverters.Register(typeof(object), typeof(double), (TypeConverter)delegate(ref object v) { return (v is double num) ? num : 0.0; }); } } private static readonly ConversionRegistry s_GlobalConverters; static TypeConversion() { s_GlobalConverters = ConversionRegistry.Create(); PrimitiveConverters.Register(); } public static void Register(TypeConverter converter) { s_GlobalConverters.Register(typeof(TSource), typeof(TDestination), converter); } public static TDestination Convert(ref TSource value) { if (!TryConvert(ref value, out var destination)) { throw new InvalidOperationException($"TypeConversion no converter has been registered for SrcType=[{typeof(TSource)}] to DstType=[{typeof(TDestination)}]"); } return destination; } public static bool TryConvert(ref TSource source, out TDestination destination) { if (s_GlobalConverters.TryGetConverter(typeof(TSource), typeof(TDestination), out var converter)) { destination = ((TypeConverter)converter)(ref source); return true; } if (typeof(TSource).IsValueType && typeof(TSource) == typeof(TDestination)) { destination = UnsafeUtility.As(ref source); return true; } if (TypeTraits.IsNullable) { if (TypeTraits.IsNullable && Nullable.GetUnderlyingType(typeof(TDestination)) != Nullable.GetUnderlyingType(typeof(TSource))) { destination = default(TDestination); return false; } Type underlyingType = Nullable.GetUnderlyingType(typeof(TDestination)); if (underlyingType.IsEnum) { Type underlyingType2 = Enum.GetUnderlyingType(underlyingType); object value = System.Convert.ChangeType(source, underlyingType2); destination = (TDestination)Enum.ToObject(underlyingType, value); return true; } if (source == null) { destination = default(TDestination); return true; } destination = (TDestination)System.Convert.ChangeType(source, underlyingType); return true; } if (TypeTraits.IsNullable && typeof(TDestination) == Nullable.GetUnderlyingType(typeof(TSource))) { if (source == null) { destination = default(TDestination); return false; } destination = (TDestination)(object)source; return true; } if (TypeTraits.IsUnityObject && TryConvertToUnityEngineObject(source, out destination)) { return true; } if (TypeTraits.IsEnum) { if (typeof(TSource) == typeof(string)) { try { destination = (TDestination)Enum.Parse(typeof(TDestination), (string)(object)source); } catch (ArgumentException) { destination = default(TDestination); return false; } return true; } if (IsNumericType(typeof(TSource))) { destination = UnsafeUtility.As(ref source); return true; } } TSource val = source; if (val is TDestination val2) { destination = val2; return true; } if (typeof(TDestination).IsAssignableFrom(typeof(TSource))) { destination = (TDestination)(object)source; return true; } destination = default(TDestination); return false; } private static bool TryConvertToUnityEngineObject(TSource source, out TDestination destination) { if (!typeof(Object).IsAssignableFrom(typeof(TDestination))) { destination = default(TDestination); return false; } if (typeof(Object).IsAssignableFrom(typeof(TSource)) || source is Object) { if (source == null) { destination = default(TDestination); return true; } if (typeof(TDestination) == typeof(Object)) { destination = (TDestination)(object)source; return true; } } if (s_GlobalConverters.TryGetConverter(typeof(TSource), typeof(Object), out var converter)) { Object val = ((TypeConverter)converter)(ref source); destination = (TDestination)(object)val; return Object.op_Implicit(val); } destination = default(TDestination); return false; } private static bool IsNumericType(Type t) { TypeCode typeCode = Type.GetTypeCode(t); TypeCode typeCode2 = typeCode; if ((uint)(typeCode2 - 5) <= 10u) { return true; } return false; } } public static class TypeTraits { public static bool IsContainer(Type type) { if (null == type) { throw new ArgumentNullException("type"); } return !type.IsPrimitive && !type.IsPointer && !type.IsEnum && !(type == typeof(string)); } } public static class TypeTraits { public static bool IsValueType { get; } public static bool IsPrimitive { get; } public static bool IsInterface { get; } public static bool IsAbstract { get; } public static bool IsArray { get; } public static bool IsMultidimensionalArray { get; } public static bool IsEnum { get; } public static bool IsEnumFlags { get; } public static bool IsNullable { get; } public static bool IsObject { get; } public static bool IsString { get; } public static bool IsContainer { get; } public static bool CanBeNull { get; } public static bool IsPrimitiveOrString { get; } public static bool IsAbstractOrInterface { get; } public static bool IsUnityObject { get; } public static bool IsLazyLoadReference { get; } static TypeTraits() { Type typeFromHandle = typeof(T); IsValueType = typeFromHandle.IsValueType; IsPrimitive = typeFromHandle.IsPrimitive; IsInterface = typeFromHandle.IsInterface; IsAbstract = typeFromHandle.IsAbstract; IsArray = typeFromHandle.IsArray; IsEnum = typeFromHandle.IsEnum; IsEnumFlags = IsEnum && typeFromHandle.GetCustomAttribute() != null; IsNullable = Nullable.GetUnderlyingType(typeof(T)) != null; IsMultidimensionalArray = IsArray && typeof(T).GetArrayRank() != 1; IsObject = typeFromHandle == typeof(object); IsString = typeFromHandle == typeof(string); IsContainer = TypeTraits.IsContainer(typeFromHandle); CanBeNull = !IsValueType; IsPrimitiveOrString = IsPrimitive || IsString; IsAbstractOrInterface = IsAbstract || IsInterface; CanBeNull |= IsNullable; IsLazyLoadReference = typeFromHandle.IsGenericType && typeFromHandle.GetGenericTypeDefinition() == typeof(LazyLoadReference<>); IsUnityObject = typeof(Object).IsAssignableFrom(typeFromHandle); } } public enum InstantiationKind { Activator, PropertyBagOverride, NotInstantiatable } internal interface IConstructor { InstantiationKind InstantiationKind { get; } } internal interface IConstructor : IConstructor { T Instantiate(); } internal interface IConstructorWithCount : IConstructor { T InstantiateWithCount(int count); } public static class TypeUtility { private interface ITypeConstructor { bool CanBeInstantiated { get; } object Instantiate(); } private interface ITypeConstructor : ITypeConstructor { new T Instantiate(); void SetExplicitConstructor(Func constructor); } private class TypeConstructor : ITypeConstructor, ITypeConstructor { private Func m_ExplicitConstructor; private Func m_ImplicitConstructor; private IConstructor m_OverrideConstructor; bool ITypeConstructor.CanBeInstantiated { get { if (m_ExplicitConstructor != null) { return true; } if (m_OverrideConstructor != null) { if (m_OverrideConstructor.InstantiationKind == InstantiationKind.NotInstantiatable) { return false; } if (m_OverrideConstructor.InstantiationKind == InstantiationKind.PropertyBagOverride) { return true; } } return m_ImplicitConstructor != null; } } public TypeConstructor() { m_OverrideConstructor = PropertyBagStore.GetPropertyBag() as IConstructor; SetImplicitConstructor(); } private void SetImplicitConstructor() { Type typeFromHandle = typeof(T); if (typeFromHandle.IsValueType) { m_ImplicitConstructor = CreateValueTypeInstance; } else if (!typeFromHandle.IsAbstract) { if (typeof(ScriptableObject).IsAssignableFrom(typeFromHandle)) { m_ImplicitConstructor = CreateScriptableObjectInstance; } else if (null != typeFromHandle.GetConstructor(Array.Empty())) { m_ImplicitConstructor = CreateClassInstance; } } } private static T CreateValueTypeInstance() { return default(T); } private static T CreateScriptableObjectInstance() { return (T)(object)ScriptableObject.CreateInstance(typeof(T)); } private static T CreateClassInstance() { return Activator.CreateInstance(); } public void SetExplicitConstructor(Func constructor) { m_ExplicitConstructor = constructor; } T ITypeConstructor.Instantiate() { if (m_ExplicitConstructor != null) { return m_ExplicitConstructor(); } if (m_OverrideConstructor != null) { if (m_OverrideConstructor.InstantiationKind == InstantiationKind.NotInstantiatable) { throw new InvalidOperationException("The type '" + typeof(T).Name + "' is not constructable."); } if (m_OverrideConstructor.InstantiationKind == InstantiationKind.PropertyBagOverride) { return m_OverrideConstructor.Instantiate(); } } if (m_ImplicitConstructor != null) { return m_ImplicitConstructor(); } throw new InvalidOperationException("The type '" + typeof(T).Name + "' is not constructable."); } object ITypeConstructor.Instantiate() { return ((ITypeConstructor)this).Instantiate(); } } private class NonConstructable : ITypeConstructor { bool ITypeConstructor.CanBeInstantiated => false; public object Instantiate() { throw new InvalidOperationException("The type is not instantiatable."); } } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct Cache { public static ITypeConstructor TypeConstructor; } private class TypeConstructorVisitor : ITypeVisitor { public ITypeConstructor TypeConstructor; public void Visit() { TypeConstructor = CreateTypeConstructor(); } } private static readonly ConcurrentDictionary s_TypeConstructors; private static readonly MethodInfo s_CreateTypeConstructor; private static readonly ConcurrentDictionary s_CachedResolvedName; private static readonly ObjectPool s_Builders; private static readonly object syncedPoolObject; static TypeUtility() { s_TypeConstructors = new ConcurrentDictionary(); syncedPoolObject = new object(); s_CachedResolvedName = new ConcurrentDictionary(); s_Builders = new ObjectPool((Func)(() => new StringBuilder()), (Action)null, (Action)delegate(StringBuilder sb) { sb.Clear(); }, (Action)null, true, 10, 10000); SetExplicitInstantiationMethod(() => string.Empty); MethodInfo[] methods = typeof(TypeUtility).GetMethods(BindingFlags.Static | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "CreateTypeConstructor") && methodInfo.IsGenericMethod) { s_CreateTypeConstructor = methodInfo; break; } } if (null == s_CreateTypeConstructor) { throw new InvalidProgramException(); } } public static string GetTypeDisplayName(Type type) { if (s_CachedResolvedName.TryGetValue(type, out var value)) { return value; } int argIndex = 0; value = GetTypeDisplayName(type, type.GetGenericArguments(), ref argIndex); s_CachedResolvedName[type] = value; return value; } private static string GetTypeDisplayName(Type type, IReadOnlyList args, ref int argIndex) { if (type == typeof(int)) { return "int"; } if (type == typeof(uint)) { return "uint"; } if (type == typeof(short)) { return "short"; } if (type == typeof(ushort)) { return "ushort"; } if (type == typeof(byte)) { return "byte"; } if (type == typeof(char)) { return "char"; } if (type == typeof(bool)) { return "bool"; } if (type == typeof(long)) { return "long"; } if (type == typeof(ulong)) { return "ulong"; } if (type == typeof(float)) { return "float"; } if (type == typeof(double)) { return "double"; } if (type == typeof(string)) { return "string"; } string text = type.Name; if (type.IsGenericParameter) { return text; } if (type.IsNested) { text = GetTypeDisplayName(type.DeclaringType, args, ref argIndex) + "." + text; } if (!type.IsGenericType) { return text; } int num = text.IndexOf('`'); int num2 = type.GetGenericArguments().Length; if (num > -1) { num2 = int.Parse(text.Substring(num + 1)); text = text.Remove(num); } StringBuilder stringBuilder = null; lock (syncedPoolObject) { stringBuilder = s_Builders.Get(); } try { int num3 = 0; while (num3 < num2 && argIndex < args.Count) { if (num3 != 0) { stringBuilder.Append(", "); } stringBuilder.Append(GetTypeDisplayName(args[argIndex])); num3++; argIndex++; } if (stringBuilder.Length > 0) { text = $"{text}<{stringBuilder}>"; } } finally { lock (syncedPoolObject) { s_Builders.Release(stringBuilder); } } return text; } public static Type GetRootType(this Type type) { if (type.IsInterface) { return null; } Type type2 = (type.IsValueType ? typeof(ValueType) : typeof(object)); while (type2 != type.BaseType) { type = type.BaseType; } return type; } [Preserve] private static ITypeConstructor CreateTypeConstructor(Type type) { IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(type); if (propertyBag != null) { TypeConstructorVisitor typeConstructorVisitor = new TypeConstructorVisitor(); propertyBag.Accept(typeConstructorVisitor); return typeConstructorVisitor.TypeConstructor; } if (type.ContainsGenericParameters) { NonConstructable nonConstructable = new NonConstructable(); s_TypeConstructors[type] = nonConstructable; return nonConstructable; } return s_CreateTypeConstructor.MakeGenericMethod(type).Invoke(null, null) as ITypeConstructor; } private static ITypeConstructor CreateTypeConstructor() { TypeConstructor typeConstructor = (TypeConstructor)(Cache.TypeConstructor = new TypeConstructor()); s_TypeConstructors[typeof(T)] = typeConstructor; return typeConstructor; } private static ITypeConstructor GetTypeConstructor(Type type) { ITypeConstructor value; return s_TypeConstructors.TryGetValue(type, out value) ? value : CreateTypeConstructor(type); } private static ITypeConstructor GetTypeConstructor() { return (Cache.TypeConstructor != null) ? Cache.TypeConstructor : CreateTypeConstructor(); } public static bool CanBeInstantiated(Type type) { return GetTypeConstructor(type).CanBeInstantiated; } public static bool CanBeInstantiated() { return GetTypeConstructor().CanBeInstantiated; } public static void SetExplicitInstantiationMethod(Func constructor) { GetTypeConstructor().SetExplicitConstructor(constructor); } public static T Instantiate() { ITypeConstructor typeConstructor = GetTypeConstructor(); CheckCanBeInstantiated(typeConstructor); return typeConstructor.Instantiate(); } public static bool TryInstantiate(out T instance) { ITypeConstructor typeConstructor = GetTypeConstructor(); if (typeConstructor.CanBeInstantiated) { instance = typeConstructor.Instantiate(); return true; } instance = default(T); return false; } public static T Instantiate(Type derivedType) { ITypeConstructor typeConstructor = GetTypeConstructor(derivedType); CheckIsAssignableFrom(typeof(T), derivedType); CheckCanBeInstantiated(typeConstructor, derivedType); return (T)typeConstructor.Instantiate(); } public static bool TryInstantiate(Type derivedType, out T value) { if (!typeof(T).IsAssignableFrom(derivedType)) { value = default(T); value = default(T); return false; } ITypeConstructor typeConstructor = GetTypeConstructor(derivedType); if (!typeConstructor.CanBeInstantiated) { value = default(T); return false; } value = (T)typeConstructor.Instantiate(); return true; } public static TArray InstantiateArray(int count = 0) { if (count < 0) { throw new ArgumentException(string.Format("{0}: Cannot construct an array with {1}={2}", "TypeUtility", "count", count)); } IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(); if (propertyBag is IConstructorWithCount constructorWithCount) { return constructorWithCount.InstantiateWithCount(count); } Type typeFromHandle = typeof(TArray); if (!typeFromHandle.IsArray) { throw new ArgumentException("TypeUtility: Cannot construct an array, since " + typeof(TArray).Name + " is not an array type."); } Type elementType = typeFromHandle.GetElementType(); if (null == elementType) { throw new ArgumentException("TypeUtility: Cannot construct an array, since " + typeof(TArray).Name + ".GetElementType() returned null."); } return (TArray)(object)Array.CreateInstance(elementType, count); } public static bool TryInstantiateArray(int count, out TArray instance) { if (count < 0) { instance = default(TArray); return false; } IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(); if (propertyBag is IConstructorWithCount constructorWithCount) { try { instance = constructorWithCount.InstantiateWithCount(count); return true; } catch { } } Type typeFromHandle = typeof(TArray); if (!typeFromHandle.IsArray) { instance = default(TArray); return false; } Type elementType = typeFromHandle.GetElementType(); if (null == elementType) { instance = default(TArray); return false; } instance = (TArray)(object)Array.CreateInstance(elementType, count); return true; } public static TArray InstantiateArray(Type derivedType, int count = 0) { if (count < 0) { throw new ArgumentException(string.Format("{0}: Cannot instantiate an array with {1}={2}", "TypeUtility", "count", count)); } IPropertyBag propertyBag = PropertyBagStore.GetPropertyBag(derivedType); if (propertyBag is IConstructorWithCount constructorWithCount) { return constructorWithCount.InstantiateWithCount(count); } Type typeFromHandle = typeof(TArray); if (!typeFromHandle.IsArray) { throw new ArgumentException("TypeUtility: Cannot instantiate an array, since " + typeof(TArray).Name + " is not an array type."); } Type elementType = typeFromHandle.GetElementType(); if (null == elementType) { throw new ArgumentException("TypeUtility: Cannot instantiate an array, since " + typeof(TArray).Name + ".GetElementType() returned null."); } return (TArray)(object)Array.CreateInstance(elementType, count); } private static void CheckIsAssignableFrom(Type type, Type derivedType) { if (!type.IsAssignableFrom(derivedType)) { throw new ArgumentException("Could not create instance of type `" + derivedType.Name + "` and convert to `" + type.Name + "`: The given type is not assignable to target type."); } } private static void CheckCanBeInstantiated(ITypeConstructor constructor) { if (!constructor.CanBeInstantiated) { throw new InvalidOperationException("Type `" + typeof(T).Name + "` could not be instantiated. A parameter-less constructor or an explicit construction method is required."); } } private static void CheckCanBeInstantiated(ITypeConstructor constructor, Type type) { if (!constructor.CanBeInstantiated) { throw new InvalidOperationException("Type `" + type.Name + "` could not be instantiated. A parameter-less constructor or an explicit construction method is required."); } } } } namespace Unity.Properties.Internal { internal interface IAttributes { List Attributes { get; set; } void AddAttribute(Attribute attribute); void AddAttributes(IEnumerable attributes); AttributesScope CreateAttributesScope(IAttributes attributes); } [VisibleToOtherModules(new string[] { "UnityEditor.PropertiesModule" })] internal static class PropertiesInitialization { [RequiredByNativeCode(false)] public static void InitializeProperties() { PropertyBagStore.CreatePropertyBagProvider(); PropertyBag.Register(new ColorPropertyBag()); PropertyBag.Register(new Vector2PropertyBag()); PropertyBag.Register(new Vector3PropertyBag()); PropertyBag.Register(new Vector4PropertyBag()); PropertyBag.Register(new Vector2IntPropertyBag()); PropertyBag.Register(new Vector3IntPropertyBag()); PropertyBag.Register(new RectPropertyBag()); PropertyBag.Register(new RectIntPropertyBag()); PropertyBag.Register(new BoundsPropertyBag()); PropertyBag.Register(new BoundsIntPropertyBag()); PropertyBag.Register(new SystemVersionPropertyBag()); } } internal class ColorPropertyBag : ContainerPropertyBag { private class RProperty : Property { public override string Name => "r"; public override bool IsReadOnly => false; public override float GetValue(ref Color container) { return container.r; } public override void SetValue(ref Color container, float value) { container.r = value; } } private class GProperty : Property { public override string Name => "g"; public override bool IsReadOnly => false; public override float GetValue(ref Color container) { return container.g; } public override void SetValue(ref Color container, float value) { container.g = value; } } private class BProperty : Property { public override string Name => "b"; public override bool IsReadOnly => false; public override float GetValue(ref Color container) { return container.b; } public override void SetValue(ref Color container, float value) { container.b = value; } } private class AProperty : Property { public override string Name => "a"; public override bool IsReadOnly => false; public override float GetValue(ref Color container) { return container.a; } public override void SetValue(ref Color container, float value) { container.a = value; } } public ColorPropertyBag() { AddProperty(new RProperty()); AddProperty(new GProperty()); AddProperty(new BProperty()); AddProperty(new AProperty()); } } internal class Vector2PropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override float GetValue(ref Vector2 container) { return container.x; } public override void SetValue(ref Vector2 container, float value) { container.x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override float GetValue(ref Vector2 container) { return container.y; } public override void SetValue(ref Vector2 container, float value) { container.y = value; } } public Vector2PropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); } } internal class Vector3PropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override float GetValue(ref Vector3 container) { return container.x; } public override void SetValue(ref Vector3 container, float value) { container.x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override float GetValue(ref Vector3 container) { return container.y; } public override void SetValue(ref Vector3 container, float value) { container.y = value; } } private class ZProperty : Property { public override string Name => "z"; public override bool IsReadOnly => false; public override float GetValue(ref Vector3 container) { return container.z; } public override void SetValue(ref Vector3 container, float value) { container.z = value; } } public Vector3PropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); AddProperty(new ZProperty()); } } internal class Vector4PropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override float GetValue(ref Vector4 container) { return container.x; } public override void SetValue(ref Vector4 container, float value) { container.x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override float GetValue(ref Vector4 container) { return container.y; } public override void SetValue(ref Vector4 container, float value) { container.y = value; } } private class ZProperty : Property { public override string Name => "z"; public override bool IsReadOnly => false; public override float GetValue(ref Vector4 container) { return container.z; } public override void SetValue(ref Vector4 container, float value) { container.z = value; } } private class WProperty : Property { public override string Name => "w"; public override bool IsReadOnly => false; public override float GetValue(ref Vector4 container) { return container.w; } public override void SetValue(ref Vector4 container, float value) { container.w = value; } } public Vector4PropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); AddProperty(new ZProperty()); AddProperty(new WProperty()); } } internal class Vector2IntPropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override int GetValue(ref Vector2Int container) { return ((Vector2Int)(ref container)).x; } public override void SetValue(ref Vector2Int container, int value) { ((Vector2Int)(ref container)).x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override int GetValue(ref Vector2Int container) { return ((Vector2Int)(ref container)).y; } public override void SetValue(ref Vector2Int container, int value) { ((Vector2Int)(ref container)).y = value; } } public Vector2IntPropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); } } internal class Vector3IntPropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override int GetValue(ref Vector3Int container) { return ((Vector3Int)(ref container)).x; } public override void SetValue(ref Vector3Int container, int value) { ((Vector3Int)(ref container)).x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override int GetValue(ref Vector3Int container) { return ((Vector3Int)(ref container)).y; } public override void SetValue(ref Vector3Int container, int value) { ((Vector3Int)(ref container)).y = value; } } private class ZProperty : Property { public override string Name => "z"; public override bool IsReadOnly => false; public override int GetValue(ref Vector3Int container) { return ((Vector3Int)(ref container)).z; } public override void SetValue(ref Vector3Int container, int value) { ((Vector3Int)(ref container)).z = value; } } public Vector3IntPropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); AddProperty(new ZProperty()); } } internal class RectPropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override float GetValue(ref Rect container) { return ((Rect)(ref container)).x; } public override void SetValue(ref Rect container, float value) { ((Rect)(ref container)).x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override float GetValue(ref Rect container) { return ((Rect)(ref container)).y; } public override void SetValue(ref Rect container, float value) { ((Rect)(ref container)).y = value; } } private class WidthProperty : Property { public override string Name => "width"; public override bool IsReadOnly => false; public override float GetValue(ref Rect container) { return ((Rect)(ref container)).width; } public override void SetValue(ref Rect container, float value) { ((Rect)(ref container)).width = value; } } private class HeightProperty : Property { public override string Name => "height"; public override bool IsReadOnly => false; public override float GetValue(ref Rect container) { return ((Rect)(ref container)).height; } public override void SetValue(ref Rect container, float value) { ((Rect)(ref container)).height = value; } } public RectPropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); AddProperty(new WidthProperty()); AddProperty(new HeightProperty()); } } internal class RectIntPropertyBag : ContainerPropertyBag { private class XProperty : Property { public override string Name => "x"; public override bool IsReadOnly => false; public override int GetValue(ref RectInt container) { return ((RectInt)(ref container)).x; } public override void SetValue(ref RectInt container, int value) { ((RectInt)(ref container)).x = value; } } private class YProperty : Property { public override string Name => "y"; public override bool IsReadOnly => false; public override int GetValue(ref RectInt container) { return ((RectInt)(ref container)).y; } public override void SetValue(ref RectInt container, int value) { ((RectInt)(ref container)).y = value; } } private class WidthProperty : Property { public override string Name => "width"; public override bool IsReadOnly => false; public override int GetValue(ref RectInt container) { return ((RectInt)(ref container)).width; } public override void SetValue(ref RectInt container, int value) { ((RectInt)(ref container)).width = value; } } private class HeightProperty : Property { public override string Name => "height"; public override bool IsReadOnly => false; public override int GetValue(ref RectInt container) { return ((RectInt)(ref container)).height; } public override void SetValue(ref RectInt container, int value) { ((RectInt)(ref container)).height = value; } } public RectIntPropertyBag() { AddProperty(new XProperty()); AddProperty(new YProperty()); AddProperty(new WidthProperty()); AddProperty(new HeightProperty()); } } internal class BoundsPropertyBag : ContainerPropertyBag { private class CenterProperty : Property { public override string Name => "center"; public override bool IsReadOnly => false; public override Vector3 GetValue(ref Bounds container) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((Bounds)(ref container)).center; } public override void SetValue(ref Bounds container, Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((Bounds)(ref container)).center = value; } } private class ExtentsProperty : Property { public override string Name => "extents"; public override bool IsReadOnly => false; public override Vector3 GetValue(ref Bounds container) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((Bounds)(ref container)).extents; } public override void SetValue(ref Bounds container, Vector3 value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((Bounds)(ref container)).extents = value; } } public BoundsPropertyBag() { AddProperty(new CenterProperty()); AddProperty(new ExtentsProperty()); } } internal class BoundsIntPropertyBag : ContainerPropertyBag { private class PositionProperty : Property { public override string Name => "position"; public override bool IsReadOnly => false; public override Vector3Int GetValue(ref BoundsInt container) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((BoundsInt)(ref container)).position; } public override void SetValue(ref BoundsInt container, Vector3Int value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((BoundsInt)(ref container)).position = value; } } private class SizeProperty : Property { public override string Name => "size"; public override bool IsReadOnly => false; public override Vector3Int GetValue(ref BoundsInt container) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((BoundsInt)(ref container)).size; } public override void SetValue(ref BoundsInt container, Vector3Int value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((BoundsInt)(ref container)).size = value; } } public BoundsIntPropertyBag() { AddProperty(new PositionProperty()); AddProperty(new SizeProperty()); } } internal class SystemVersionPropertyBag : ContainerPropertyBag { private class MajorProperty : Property { public override string Name => "Major"; public override bool IsReadOnly => true; public MajorProperty() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown AddAttribute((Attribute)new MinAttribute(0f)); } public override int GetValue(ref Version container) { return container.Major; } public override void SetValue(ref Version container, int value) { } } private class MinorProperty : Property { public override string Name => "Minor"; public override bool IsReadOnly => true; public MinorProperty() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown AddAttribute((Attribute)new MinAttribute(0f)); } public override int GetValue(ref Version container) { return container.Minor; } public override void SetValue(ref Version container, int value) { } } private class BuildProperty : Property { public override string Name => "Build"; public override bool IsReadOnly => true; public BuildProperty() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown AddAttribute((Attribute)new MinAttribute(0f)); } public override int GetValue(ref Version container) { return container.Build; } public override void SetValue(ref Version container, int value) { } } private class RevisionProperty : Property { public override string Name => "Revision"; public override bool IsReadOnly => true; public RevisionProperty() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown AddAttribute((Attribute)new MinAttribute(0f)); } public override int GetValue(ref Version container) { return container.Revision; } public override void SetValue(ref Version container, int value) { } } public SystemVersionPropertyBag() { AddProperty(new MajorProperty()); AddProperty(new MinorProperty()); AddProperty(new BuildProperty()); AddProperty(new RevisionProperty()); } } internal interface IPropertyBagRegister { void Register(); } internal static class PropertyBagStore { [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct TypedStore { public static IPropertyBag PropertyBag; } private static readonly ConcurrentDictionary s_PropertyBags = new ConcurrentDictionary(); private static readonly List s_RegisteredTypes = new List(); private static ReflectedPropertyBagProvider s_PropertyBagProvider = null; private static ReflectedPropertyBagProvider ReflectedPropertyBagProvider => s_PropertyBagProvider ?? (s_PropertyBagProvider = new ReflectedPropertyBagProvider()); internal static List AllTypes => s_RegisteredTypes; internal static void CreatePropertyBagProvider() { s_PropertyBagProvider = new ReflectedPropertyBagProvider(); } internal static void AddPropertyBag(IPropertyBag propertyBag) { if (!TypeTraits.IsContainer) { throw new Exception($"PropertyBagStore Type=[{typeof(TContainer)}] is not a valid container type. Type can not be primitive, enum or string."); } if (TypeTraits.IsAbstractOrInterface) { throw new Exception($"PropertyBagStore Type=[{typeof(TContainer)}] is not a valid container type. Type can not be abstract or interface."); } if (TypedStore.PropertyBag != null) { IPropertyBag propertyBag2 = TypedStore.PropertyBag; if (propertyBag2.GetType().Assembly == typeof(TContainer).Assembly || (propertyBag.GetType().GetCustomAttributes().Any() && propertyBag.GetType().Assembly != typeof(TContainer).Assembly)) { return; } } TypedStore.PropertyBag = propertyBag; if (!s_PropertyBags.ContainsKey(typeof(TContainer))) { s_RegisteredTypes.Add(typeof(TContainer)); } s_PropertyBags[typeof(TContainer)] = propertyBag; } internal static IPropertyBag GetPropertyBag() { if (TypedStore.PropertyBag != null) { return TypedStore.PropertyBag; } IPropertyBag propertyBag = GetPropertyBag(typeof(TContainer)); if (propertyBag == null) { return null; } if (!(propertyBag is IPropertyBag result)) { throw new InvalidOperationException("PropertyBag type container type mismatch."); } return result; } internal static IPropertyBag GetPropertyBag(Type type) { if (s_PropertyBags.TryGetValue(type, out var value)) { return value; } if (!TypeTraits.IsContainer(type)) { return null; } if (type.IsArray && type.GetArrayRank() != 1) { return null; } if (type.IsInterface || type.IsAbstract) { return null; } if (type == typeof(object)) { return null; } value = ReflectedPropertyBagProvider.CreatePropertyBag(type); if (value == null) { s_PropertyBags.TryAdd(type, null); return null; } (value as IPropertyBagRegister)?.Register(); return value; } internal static bool Exists() { return TypedStore.PropertyBag != null; } internal static bool Exists(Type type) { return s_PropertyBags.ContainsKey(type); } internal static bool Exists(ref TContainer value) { if (!TypeTraits.CanBeNull) { return GetPropertyBag() != null; } if (EqualityComparer.Default.Equals(value, default(TContainer))) { return false; } return GetPropertyBag(value.GetType()) != null; } internal static bool TryGetPropertyBagForValue(ref TValue value, out IPropertyBag propertyBag) { if (!TypeTraits.IsContainer) { propertyBag = null; return false; } if (TypeTraits.CanBeNull && EqualityComparer.Default.Equals(value, default(TValue))) { propertyBag = GetPropertyBag(); return propertyBag != null; } if (TypeTraits.IsValueType) { propertyBag = GetPropertyBag(); return propertyBag != null; } propertyBag = GetPropertyBag(value.GetType()); return propertyBag != null; } } internal readonly struct ReadOnlyAdapterCollection { public struct Enumerator { private List m_Adapters; private int m_Index; public IPropertyVisitorAdapter Current { get; private set; } public Enumerator(ReadOnlyAdapterCollection collection) { m_Adapters = collection.m_Adapters; m_Index = 0; Current = null; } public bool MoveNext() { if (m_Adapters == null) { return false; } if (m_Index >= m_Adapters.Count) { return false; } Current = m_Adapters[m_Index]; m_Index++; return true; } private void Reset() { m_Index = 0; Current = null; } } private readonly List m_Adapters; public ReadOnlyAdapterCollection(List adapters) { m_Adapters = adapters; } public Enumerator GetEnumerator() { return new Enumerator(this); } } internal class ReflectedPropertyBagAttribute : Attribute { } [ReflectedPropertyBag] internal class ReflectedPropertyBag : ContainerPropertyBag { internal new void AddProperty(Property property) { TContainer container = default(TContainer); if (TryGetProperty(ref container, property.Name, out var property2)) { if (!(property2.DeclaredValueType() == typeof(TValue))) { Debug.LogWarning((object)("Detected multiple return types for PropertyBag=[" + TypeUtility.GetTypeDisplayName(typeof(TContainer)) + "] Property=[" + property.Name + "]. The property will use the most derived Type=[" + TypeUtility.GetTypeDisplayName(property2.DeclaredValueType()) + "] and IgnoreType=[" + TypeUtility.GetTypeDisplayName(property.DeclaredValueType()) + "].")); } } else { base.AddProperty(property); } } } internal class ReflectedPropertyBagProvider { private readonly MethodInfo m_CreatePropertyMethod; private readonly MethodInfo m_CreatePropertyBagMethod; private readonly MethodInfo m_CreateIndexedCollectionPropertyBagMethod; private readonly MethodInfo m_CreateSetPropertyBagMethod; private readonly MethodInfo m_CreateKeyValueCollectionPropertyBagMethod; private readonly MethodInfo m_CreateKeyValuePairPropertyBagMethod; private readonly MethodInfo m_CreateArrayPropertyBagMethod; private readonly MethodInfo m_CreateListPropertyBagMethod; private readonly MethodInfo m_CreateHashSetPropertyBagMethod; private readonly MethodInfo m_CreateDictionaryPropertyBagMethod; public ReflectedPropertyBagProvider() { m_CreatePropertyMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateProperty", BindingFlags.Instance | BindingFlags.NonPublic); m_CreatePropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethods(BindingFlags.Instance | BindingFlags.Public).First((MethodInfo x) => x.Name == "CreatePropertyBag" && x.IsGenericMethod); m_CreateIndexedCollectionPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateIndexedCollectionPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateSetPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateSetPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateKeyValueCollectionPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateKeyValueCollectionPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateKeyValuePairPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateKeyValuePairPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateArrayPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateArrayPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateListPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateListPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateHashSetPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateHashSetPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); m_CreateDictionaryPropertyBagMethod = typeof(ReflectedPropertyBagProvider).GetMethod("CreateDictionaryPropertyBag", BindingFlags.Instance | BindingFlags.NonPublic); } public IPropertyBag CreatePropertyBag(Type type) { if (type.IsGenericTypeDefinition) { return null; } return (IPropertyBag)m_CreatePropertyBagMethod.MakeGenericMethod(type).Invoke(this, null); } public IPropertyBag CreatePropertyBag() { if (!TypeTraits.IsContainer || TypeTraits.IsObject) { throw new InvalidOperationException("Invalid container type."); } if (typeof(TContainer).IsArray) { if (typeof(TContainer).GetArrayRank() != 1) { throw new InvalidOperationException("Properties does not support multidimensional arrays."); } return (IPropertyBag)m_CreateArrayPropertyBagMethod.MakeGenericMethod(typeof(TContainer).GetElementType()).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>))) { return (IPropertyBag)m_CreateListPropertyBagMethod.MakeGenericMethod(typeof(TContainer).GetGenericArguments().First()).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(HashSet<>))) { return (IPropertyBag)m_CreateHashSetPropertyBagMethod.MakeGenericMethod(typeof(TContainer).GetGenericArguments().First()).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<, >))) { return (IPropertyBag)m_CreateDictionaryPropertyBagMethod.MakeGenericMethod(typeof(TContainer).GetGenericArguments().First(), typeof(TContainer).GetGenericArguments().ElementAt(1)).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(IList<>))) { return (IPropertyBag)m_CreateIndexedCollectionPropertyBagMethod.MakeGenericMethod(typeof(TContainer), typeof(TContainer).GetGenericArguments().First()).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(ISet<>))) { return (IPropertyBag)m_CreateSetPropertyBagMethod.MakeGenericMethod(typeof(TContainer), typeof(TContainer).GetGenericArguments().First()).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(IDictionary<, >))) { return (IPropertyBag)m_CreateKeyValueCollectionPropertyBagMethod.MakeGenericMethod(typeof(TContainer), typeof(TContainer).GetGenericArguments().First(), typeof(TContainer).GetGenericArguments().ElementAt(1)).Invoke(this, new object[0]); } if (typeof(TContainer).IsGenericType && typeof(TContainer).GetGenericTypeDefinition().IsAssignableFrom(typeof(KeyValuePair<, >))) { Type[] array = typeof(TContainer).GetGenericArguments().ToArray(); return (IPropertyBag)m_CreateKeyValuePairPropertyBagMethod.MakeGenericMethod(array[0], array[1]).Invoke(this, new object[0]); } ReflectedPropertyBag reflectedPropertyBag = new ReflectedPropertyBag(); foreach (MemberInfo propertyMember in GetPropertyMembers(typeof(TContainer))) { MemberInfo memberInfo = propertyMember; MemberInfo memberInfo2 = memberInfo; IMemberInfo memberInfo3; if (!(memberInfo2 is FieldInfo fieldInfo)) { if (!(memberInfo2 is PropertyInfo propertyInfo)) { throw new InvalidOperationException(); } memberInfo3 = new PropertyMember(propertyInfo); } else { memberInfo3 = new FieldMember(fieldInfo); } m_CreatePropertyMethod.MakeGenericMethod(typeof(TContainer), memberInfo3.ValueType).Invoke(this, new object[2] { memberInfo3, reflectedPropertyBag }); } return reflectedPropertyBag; } [Preserve] private void CreateProperty(IMemberInfo member, ReflectedPropertyBag propertyBag) { if (!typeof(TValue).IsPointer) { propertyBag.AddProperty(new ReflectedMemberProperty(member, member.Name)); } } [Preserve] private IPropertyBag CreateIndexedCollectionPropertyBag() where TList : IList { return new IndexedCollectionPropertyBag(); } [Preserve] private IPropertyBag CreateSetPropertyBag() where TSet : ISet { return new SetPropertyBagBase(); } [Preserve] private IPropertyBag CreateKeyValueCollectionPropertyBag() where TDictionary : IDictionary { return new KeyValueCollectionPropertyBag(); } [Preserve] private IPropertyBag> CreateKeyValuePairPropertyBag() { return new KeyValuePairPropertyBag(); } [Preserve] private IPropertyBag CreateArrayPropertyBag() { return new ArrayPropertyBag(); } [Preserve] private IPropertyBag> CreateListPropertyBag() { return new ListPropertyBag(); } [Preserve] private IPropertyBag> CreateHashSetPropertyBag() { return new HashSetPropertyBag(); } [Preserve] private IPropertyBag> CreateDictionaryPropertyBag() { return new DictionaryPropertyBag(); } private static IEnumerable GetPropertyMembers(Type type) { do { IOrderedEnumerable members = from x in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) orderby x.MetadataToken select x; foreach (MemberInfo member in members) { if ((member.MemberType != MemberTypes.Field && member.MemberType != MemberTypes.Property) || member.DeclaringType != type || !IsValidMember(member)) { continue; } bool hasDontCreatePropertyAttribute = member.GetCustomAttribute() != null; bool hasCreatePropertyAttribute = member.GetCustomAttribute() != null; bool hasNonSerializedAttribute = member.GetCustomAttribute() != null; bool hasSerializedFieldAttribute = member.GetCustomAttribute() != null; bool hasSerializeReferenceAttribute = member.GetCustomAttribute() != null; if (hasDontCreatePropertyAttribute) { continue; } if (hasCreatePropertyAttribute) { yield return member; } else if (!hasNonSerializedAttribute) { if (hasSerializedFieldAttribute) { yield return member; } else if (hasSerializeReferenceAttribute) { yield return member; } else if (member is FieldInfo field && field.IsPublic) { yield return member; } } } type = type.BaseType; } while (type != null && type != typeof(object)); } private static bool IsValidMember(MemberInfo memberInfo) { if (!(memberInfo is FieldInfo fieldInfo)) { if (memberInfo is PropertyInfo propertyInfo) { return null != propertyInfo.GetMethod && !propertyInfo.GetMethod.IsStatic && IsValidPropertyType(propertyInfo.PropertyType); } return false; } return !fieldInfo.IsStatic && IsValidPropertyType(fieldInfo.FieldType); } private static bool IsValidPropertyType(Type type) { if (type.IsPointer) { return false; } return !type.IsGenericType || type.GetGenericArguments().All(IsValidPropertyType); } } internal static class ReflectionUtilities { public static string SanitizeMemberName(MemberInfo info) { return info.Name.Replace(".", "_").Replace("<", "_").Replace(">", "") .Replace("+", "_"); } } }