Skip to content

Commit

Permalink
Add TypeKey struct and fix IsArray type FullName
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
X39 committed May 11, 2024
1 parent 49cfe1c commit 412e3b5
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 17 deletions.
14 changes: 14 additions & 0 deletions X39.Util.Tests/TypeExtensionMethods/FullNameTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,18 @@ public void GenericClassTestSubClassGenericSubSubClassGenericTest()
"X39.Util.Tests.TypeExtensionMethods.Data.GenericClass<T1, T2, T3>.SubClassGeneric<T1, T2, T3>.SubSubClassGeneric<T1>",
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);
}
}
29 changes: 12 additions & 17 deletions X39.Util/TypeExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ namespace X39.Util;
public static partial class TypeExtensionMethods
{
// ReSharper disable once IdentifierTypo
internal static readonly RWLConcurrentDictionary<Type, Type> DeNulledTypeCache = new();
internal static readonly RWLConcurrentDictionary<Type, string> FullNameCache = new();
internal static readonly RWLConcurrentDictionary<Type, string> NameCache = new();
internal static readonly RWLConcurrentDictionary<Type, Type> BaseTypeCache = new();
internal static readonly RWLConcurrentDictionary<Type, bool> IsObsoleteCache = new();
internal static readonly RWLConcurrentDictionary<TypeKey, Type> DeNulledTypeCache = new();
internal static readonly RWLConcurrentDictionary<TypeKey, string> FullNameCache = new();
internal static readonly RWLConcurrentDictionary<TypeKey, string> NameCache = new();
internal static readonly RWLConcurrentDictionary<TypeKey, Type> BaseTypeCache = new();
internal static readonly RWLConcurrentDictionary<TypeKey, bool> IsObsoleteCache = new();

internal struct InstanceCacheKey : IEquatable<InstanceCacheKey>
{
Expand Down Expand Up @@ -173,17 +173,6 @@ public static string FullName(this Type t)
/// <returns></returns>
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)
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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();
}
Expand Down
84 changes: 84 additions & 0 deletions X39.Util/TypeKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
namespace X39.Util;

/// <summary>
/// Represents a key that uniquely identifies a Type.
/// </summary>
/// <remarks>
/// This is useful for using a Type as a key in a dictionary.
/// </remarks>
public readonly struct TypeKey : IEquatable<TypeKey>
{
/// <inheritdoc />
public bool Equals(TypeKey other)
{
return Type.IsEquivalentTo(other.Type);
}

/// <inheritdoc />
public override bool Equals(object? obj)
{
return obj is TypeKey other && Equals(other);
}

/// <inheritdoc />
public override int GetHashCode()
{
return Type.GetHashCode();
}

/// <summary>
/// Determines whether two <see cref="TypeKey"/> objects are equal.
/// </summary>
/// <param name="left">The left <see cref="TypeKey"/> object.</param>
/// <param name="right">The right <see cref="TypeKey"/> object.</param>
/// <returns>
/// <see langword="true"/> if the specified <see cref="TypeKey"/> objects are equal; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator ==(TypeKey left, TypeKey right)
{
return left.Equals(right);
}

/// <summary>
/// Determines whether two <see cref="TypeKey"/> objects are not equal.
/// </summary>
/// <param name="left">The left <see cref="TypeKey"/> object.</param>
/// <param name="right">The right <see cref="TypeKey"/> object.</param>
/// <returns>
/// <see langword="true"/> if the specified <see cref="TypeKey"/> objects are not equal; otherwise, <see langword="false"/>.
/// </returns>
public static bool operator !=(TypeKey left, TypeKey right)
{
return !left.Equals(right);
}

/// <summary>
/// Represents a key that uniquely identifies a Type.
/// </summary>
/// <remarks>
/// This is useful for using a Type as a key in a dictionary.
/// </remarks>
public TypeKey(Type type)
{
Type = type;
}

/// <summary>
/// The Type that this TypeKey represents.
/// </summary>
public Type Type { get; }

/// <summary>
/// Defines an implicit operator that converts a TypeKey to a Type.
/// </summary>
/// <param name="key">The TypeKey to be converted.</param>
/// <returns>The corresponding Type object.</returns>
public static implicit operator Type(TypeKey key) => key.Type;

/// <summary>
/// Defines an implicit operator that converts a Type object to a TypeKey.
/// </summary>
/// <param name="type">The Type object to be converted.</param>
/// <returns>The corresponding TypeKey object.</returns>
public static implicit operator TypeKey(Type type) => new TypeKey(type);
}

0 comments on commit 412e3b5

Please sign in to comment.