From 412e3b5c84c5f4d8caf20ae903e2436433fdbdb4 Mon Sep 17 00:00:00 2001 From: Marco Silipo Date: Sun, 12 May 2024 01:45:46 +0200 Subject: [PATCH] Add TypeKey struct and fix IsArray type FullName Introduced a new struct, TypeKey, to uniquely identify a Type and facilitate its usage in a dictionary as a key. Updated TypeExtensionMethods to make use of this new struct for its various caches, improving organization and access to these cached values. Added a new test method in FullNameTest.cs to verify cache functionality. --- .../TypeExtensionMethods/FullNameTest.cs | 14 ++++ X39.Util/TypeExtensionMethods.cs | 29 +++---- X39.Util/TypeKey.cs | 84 +++++++++++++++++++ 3 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 X39.Util/TypeKey.cs diff --git a/X39.Util.Tests/TypeExtensionMethods/FullNameTest.cs b/X39.Util.Tests/TypeExtensionMethods/FullNameTest.cs index d1915b1..1b67382 100644 --- a/X39.Util.Tests/TypeExtensionMethods/FullNameTest.cs +++ b/X39.Util.Tests/TypeExtensionMethods/FullNameTest.cs @@ -117,4 +117,18 @@ public void GenericClassTestSubClassGenericSubSubClassGenericTest() "X39.Util.Tests.TypeExtensionMethods.Data.GenericClass.SubClassGeneric.SubSubClassGeneric", typeof(Data.GenericClass<,,>.SubClassGeneric<,,>.SubSubClassGeneric<>).FullNameUncached()); } + + [Test] + [NonParallelizable] + public void ValidateCacheWorks() + { + Util.TypeExtensionMethods.FullNameCache.Clear(); + Assert.AreEqual(Util.TypeExtensionMethods.FullNameCache.Count, 0); + typeof(Data.GenericClass<,,>).FullNameUncached(); + Assert.AreEqual(Util.TypeExtensionMethods.FullNameCache.Count, 0); + typeof(Data.GenericClass<,,>).FullName(); + Assert.AreEqual(Util.TypeExtensionMethods.FullNameCache.Count, 1); + typeof(Data.GenericClass<,,>).FullName(); + Assert.AreEqual(Util.TypeExtensionMethods.FullNameCache.Count, 1); + } } \ No newline at end of file diff --git a/X39.Util/TypeExtensionMethods.cs b/X39.Util/TypeExtensionMethods.cs index bbcf555..9c94a87 100644 --- a/X39.Util/TypeExtensionMethods.cs +++ b/X39.Util/TypeExtensionMethods.cs @@ -19,11 +19,11 @@ namespace X39.Util; public static partial class TypeExtensionMethods { // ReSharper disable once IdentifierTypo - internal static readonly RWLConcurrentDictionary DeNulledTypeCache = new(); - internal static readonly RWLConcurrentDictionary FullNameCache = new(); - internal static readonly RWLConcurrentDictionary NameCache = new(); - internal static readonly RWLConcurrentDictionary BaseTypeCache = new(); - internal static readonly RWLConcurrentDictionary IsObsoleteCache = new(); + internal static readonly RWLConcurrentDictionary DeNulledTypeCache = new(); + internal static readonly RWLConcurrentDictionary FullNameCache = new(); + internal static readonly RWLConcurrentDictionary NameCache = new(); + internal static readonly RWLConcurrentDictionary BaseTypeCache = new(); + internal static readonly RWLConcurrentDictionary IsObsoleteCache = new(); internal struct InstanceCacheKey : IEquatable { @@ -173,17 +173,6 @@ public static string FullName(this Type t) /// public static string FullNameUncached(this Type t) { - /* - X39.Util.Tests.TypeExtensionMethods.Data.GenericClass`3+SubClassGeneric`3 - X39.Util.Tests.TypeExtensionMethods.Data.GenericClass`3 - X39.Util.Tests.TypeExtensionMethods.Data.GenericClass`3+SubClassGeneric`3[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] - System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[X39.Util.Tests.TypeExtensionMethods.Data.GenericClass`3+SubClassGeneric`3[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], X39.Util.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] - "System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[X39.Util.Tests.TypeExtensionMethods.Data.GenericClass`3[[System.Int32, System.Private.CoreLib, Version=7.0.…" - "System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=ne…" - "System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]" - "System.Collections.Generic.KeyValuePair`2[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]" - System.String - */ if (t.FullName is null) return t.Name; if (t.IsGenericParameter) @@ -218,6 +207,12 @@ public static string FullNameUncached(this Type t) } } + if (t.IsArray) + { + builder.Append('['); + builder.Append(',', t.GetArrayRank()); + builder.Append(']'); + } return builder.ToString(); } @@ -251,7 +246,7 @@ public static string NameUncached(this Type t) gravisIndex = t.Name.Length; builder.Append(t.Name.Substring(0, gravisIndex)); builder.Append('<'); - builder.Append(string.Join(", ", t.GetGenericArguments().Select(FullName))); + builder.Append(string.Join(", ", t.GetGenericArguments().Select(FullNameUncached))); builder.Append('>'); return builder.ToString(); } diff --git a/X39.Util/TypeKey.cs b/X39.Util/TypeKey.cs new file mode 100644 index 0000000..4b80627 --- /dev/null +++ b/X39.Util/TypeKey.cs @@ -0,0 +1,84 @@ +namespace X39.Util; + +/// +/// Represents a key that uniquely identifies a Type. +/// +/// +/// This is useful for using a Type as a key in a dictionary. +/// +public readonly struct TypeKey : IEquatable +{ + /// + public bool Equals(TypeKey other) + { + return Type.IsEquivalentTo(other.Type); + } + + /// + public override bool Equals(object? obj) + { + return obj is TypeKey other && Equals(other); + } + + /// + public override int GetHashCode() + { + return Type.GetHashCode(); + } + + /// + /// Determines whether two objects are equal. + /// + /// The left object. + /// The right object. + /// + /// if the specified objects are equal; otherwise, . + /// + public static bool operator ==(TypeKey left, TypeKey right) + { + return left.Equals(right); + } + + /// + /// Determines whether two objects are not equal. + /// + /// The left object. + /// The right object. + /// + /// if the specified objects are not equal; otherwise, . + /// + public static bool operator !=(TypeKey left, TypeKey right) + { + return !left.Equals(right); + } + + /// + /// Represents a key that uniquely identifies a Type. + /// + /// + /// This is useful for using a Type as a key in a dictionary. + /// + public TypeKey(Type type) + { + Type = type; + } + + /// + /// The Type that this TypeKey represents. + /// + public Type Type { get; } + + /// + /// Defines an implicit operator that converts a TypeKey to a Type. + /// + /// The TypeKey to be converted. + /// The corresponding Type object. + public static implicit operator Type(TypeKey key) => key.Type; + + /// + /// Defines an implicit operator that converts a Type object to a TypeKey. + /// + /// The Type object to be converted. + /// The corresponding TypeKey object. + public static implicit operator TypeKey(Type type) => new TypeKey(type); +} \ No newline at end of file