mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-16 13:15:07 +00:00
fix: Improved threadsafety for TypeExtensions
This commit is contained in:
committed by
Chris Cameron
parent
9819c44dcc
commit
e61dcd8596
@@ -60,11 +60,17 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeAllTypes;
|
private static readonly Dictionary<Type, Type[]> s_TypeAllTypes;
|
||||||
|
private static readonly SafeCriticalSection s_TypeAllTypesSection;
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
||||||
|
private static readonly SafeCriticalSection s_TypeBaseTypesSection;
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
||||||
|
private static readonly SafeCriticalSection s_TypeImmediateInterfacesSection;
|
||||||
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
||||||
|
private static readonly SafeCriticalSection s_TypeMinimalInterfacesSection;
|
||||||
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
|
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
|
||||||
|
private static readonly SafeCriticalSection s_TypeToMinimalNameSection;
|
||||||
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
||||||
|
private static readonly SafeCriticalSection s_TypeToNameWithoutAssemblyDetailsSection;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Static constructor.
|
/// Static constructor.
|
||||||
@@ -72,11 +78,17 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
static TypeExtensions()
|
static TypeExtensions()
|
||||||
{
|
{
|
||||||
s_TypeAllTypes = new Dictionary<Type, Type[]>();
|
s_TypeAllTypes = new Dictionary<Type, Type[]>();
|
||||||
|
s_TypeAllTypesSection = new SafeCriticalSection();
|
||||||
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
||||||
|
s_TypeBaseTypesSection = new SafeCriticalSection();
|
||||||
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
||||||
|
s_TypeImmediateInterfacesSection = new SafeCriticalSection();
|
||||||
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
||||||
|
s_TypeMinimalInterfacesSection = new SafeCriticalSection();
|
||||||
s_TypeToMinimalName = new Dictionary<Type, string>();
|
s_TypeToMinimalName = new Dictionary<Type, string>();
|
||||||
|
s_TypeToMinimalNameSection = new SafeCriticalSection();
|
||||||
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
||||||
|
s_TypeToNameWithoutAssemblyDetailsSection = new SafeCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -246,16 +258,24 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
Type[] types;
|
Type[] types;
|
||||||
if (!s_TypeAllTypes.TryGetValue(extends, out types))
|
s_TypeAllTypesSection.Enter();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
types = extends.GetBaseTypes()
|
if (s_TypeAllTypes.TryGetValue(extends, out types))
|
||||||
.Concat(extends.GetInterfaces())
|
return types;
|
||||||
.Prepend(extends)
|
}
|
||||||
.ToArray();
|
finally
|
||||||
|
{
|
||||||
s_TypeAllTypes[extends] = types;
|
s_TypeAllTypesSection.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
types = extends.GetBaseTypes()
|
||||||
|
.Concat(extends.GetInterfaces())
|
||||||
|
.Prepend(extends)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
s_TypeAllTypesSection.Execute(() => s_TypeAllTypes[extends] = types);
|
||||||
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,11 +291,20 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
Type[] types;
|
Type[] types;
|
||||||
if (!s_TypeBaseTypes.TryGetValue(extends, out types))
|
|
||||||
|
s_TypeBaseTypesSection.Enter();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
types = GetBaseTypesIterator(extends).ToArray();
|
if (s_TypeBaseTypes.TryGetValue(extends, out types))
|
||||||
s_TypeBaseTypes[extends] = types;
|
return types;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
s_TypeBaseTypesSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
types = GetBaseTypesIterator(extends).ToArray();
|
||||||
|
s_TypeBaseTypesSection.Execute(() => s_TypeBaseTypes[extends] = types);
|
||||||
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
@@ -309,20 +338,30 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
Type[] immediateInterfaces;
|
Type[] immediateInterfaces;
|
||||||
if (!s_TypeImmediateInterfaces.TryGetValue(extends, out immediateInterfaces))
|
|
||||||
|
s_TypeImmediateInterfacesSection.Enter();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
IEnumerable<Type> allInterfaces = extends.GetInterfaces();
|
if (s_TypeImmediateInterfaces.TryGetValue(extends, out immediateInterfaces))
|
||||||
|
return immediateInterfaces;
|
||||||
IEnumerable<Type> childInterfaces =
|
|
||||||
extends.GetAllTypes()
|
|
||||||
.Except(extends)
|
|
||||||
.SelectMany(t => t.GetImmediateInterfaces())
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
immediateInterfaces = allInterfaces.Except(childInterfaces).ToArray();
|
|
||||||
|
|
||||||
s_TypeImmediateInterfaces[extends] = immediateInterfaces;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
s_TypeImmediateInterfacesSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IEnumerable<Type> allInterfaces = extends.GetInterfaces();
|
||||||
|
|
||||||
|
IEnumerable<Type> childInterfaces =
|
||||||
|
extends.GetAllTypes()
|
||||||
|
.Except(extends)
|
||||||
|
.SelectMany(t => t.GetImmediateInterfaces())
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
immediateInterfaces = allInterfaces.Except(childInterfaces).ToArray();
|
||||||
|
|
||||||
|
s_TypeImmediateInterfacesSection.Execute(() => s_TypeImmediateInterfaces[extends] = immediateInterfaces);
|
||||||
|
|
||||||
return immediateInterfaces;
|
return immediateInterfaces;
|
||||||
}
|
}
|
||||||
@@ -339,14 +378,24 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
Type[] minimalInterfaces;
|
Type[] minimalInterfaces;
|
||||||
if (!s_TypeMinimalInterfaces.TryGetValue(extends, out minimalInterfaces))
|
|
||||||
{
|
|
||||||
Type[] allInterfaces = extends.GetInterfaces();
|
|
||||||
minimalInterfaces = allInterfaces.Except(allInterfaces.SelectMany(t => t.GetInterfaces()))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
s_TypeMinimalInterfaces[extends] = minimalInterfaces;
|
|
||||||
|
s_TypeMinimalInterfacesSection.Enter();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (s_TypeMinimalInterfaces.TryGetValue(extends, out minimalInterfaces))
|
||||||
|
return minimalInterfaces;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
s_TypeMinimalInterfacesSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] allInterfaces = extends.GetInterfaces();
|
||||||
|
minimalInterfaces = allInterfaces.Except(allInterfaces.SelectMany(t => t.GetInterfaces()))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
s_TypeMinimalInterfacesSection.Execute(() => s_TypeMinimalInterfaces[extends] = minimalInterfaces);
|
||||||
|
|
||||||
return minimalInterfaces;
|
return minimalInterfaces;
|
||||||
}
|
}
|
||||||
@@ -379,47 +428,44 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
/// <param name="extends"></param>
|
/// <param name="extends"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public static string GetMinimalName([NotNull]this Type extends)
|
public static string GetMinimalName([NotNull] this Type extends)
|
||||||
{
|
{
|
||||||
if (extends == null)
|
if (extends == null)
|
||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
if (!s_TypeToMinimalName.TryGetValue(extends, out name))
|
|
||||||
|
s_TypeToMinimalNameSection.Enter();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Generics are a pain
|
if (s_TypeToMinimalName.TryGetValue(extends, out name))
|
||||||
if (extends.IsGenericType)
|
return name;
|
||||||
{
|
|
||||||
string nameWithoutAssemblyDetails = Type.GetType(extends.FullName) == null
|
|
||||||
? extends.GetNameWithoutAssemblyDetails()
|
|
||||||
: extends.FullName;
|
|
||||||
int genericStart = nameWithoutAssemblyDetails.IndexOf('[');
|
|
||||||
if (genericStart < 0)
|
|
||||||
{
|
|
||||||
name = nameWithoutAssemblyDetails;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string genericParameterNames =
|
|
||||||
string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray());
|
|
||||||
int genericEnd = nameWithoutAssemblyDetails.LastIndexOf(']');
|
|
||||||
|
|
||||||
name = new StringBuilder().Append(nameWithoutAssemblyDetails, 0, genericStart + 2)
|
|
||||||
.Append(genericParameterNames)
|
|
||||||
.Append(nameWithoutAssemblyDetails, genericEnd - 1,
|
|
||||||
nameWithoutAssemblyDetails.Length - genericEnd + 1)
|
|
||||||
.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = Type.GetType(extends.FullName) == null
|
|
||||||
? extends.GetNameWithoutAssemblyDetails()
|
|
||||||
: extends.FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_TypeToMinimalName[extends] = name;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
s_TypeToMinimalNameSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
name = Type.GetType(extends.FullName) == null
|
||||||
|
? extends.GetNameWithoutAssemblyDetails()
|
||||||
|
: extends.FullName;
|
||||||
|
// Generics are a pain
|
||||||
|
if (extends.IsGenericType)
|
||||||
|
{
|
||||||
|
int genericStart = name.IndexOf('[');
|
||||||
|
if (genericStart >= 0)
|
||||||
|
{
|
||||||
|
string genericParameterNames =
|
||||||
|
string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray());
|
||||||
|
int genericEnd = name.LastIndexOf(']');
|
||||||
|
name = new StringBuilder().Append(name, 0, genericStart + 2)
|
||||||
|
.Append(genericParameterNames)
|
||||||
|
.Append(name, genericEnd - 1,
|
||||||
|
name.Length - genericEnd + 1)
|
||||||
|
.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_TypeToMinimalNameSection.Execute(() => s_TypeToMinimalName[extends] = name);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -436,11 +482,22 @@ namespace ICD.Common.Utils.Extensions
|
|||||||
throw new ArgumentNullException("extends");
|
throw new ArgumentNullException("extends");
|
||||||
|
|
||||||
string name;
|
string name;
|
||||||
if (!s_TypeToNameWithoutAssemblyDetails.TryGetValue(extends, out name))
|
|
||||||
|
s_TypeToNameWithoutAssemblyDetailsSection.Enter();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
name = RemoveAssemblyDetails(extends.AssemblyQualifiedName);
|
if (s_TypeToNameWithoutAssemblyDetails.TryGetValue(extends, out name))
|
||||||
s_TypeToNameWithoutAssemblyDetails[extends] = name;
|
return name;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
s_TypeToNameWithoutAssemblyDetailsSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
name = RemoveAssemblyDetails(extends.AssemblyQualifiedName);
|
||||||
|
|
||||||
|
s_TypeToNameWithoutAssemblyDetailsSection.Execute(() => s_TypeToNameWithoutAssemblyDetails[extends] = name);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user