Skip to content

Commit b0a738a

Browse files
committed
Merge branch 'master-aftermerge-typehelper-changes'
2 parents ccbcd4a + 1216ee5 commit b0a738a

File tree

3 files changed

+109
-28
lines changed

3 files changed

+109
-28
lines changed

ChangeLog/7.2.0-Beta-1-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[main] DomainConfiguration.MaxNumberOfConditions is introduced
77
[main] SqlDml.Truncate() is introduced.
88
[main] WellKnown.MaxNumberOfConditions became obsolete, use new DomainConfiguration.MaxNumberOfConditions if needed
9+
[main] TypeHelper.GetSingleConstructor() and .GetSingleConstructorOrDefault() are marked obsolete
910
[main] Temporary tables cleanup now uses TRUNCATE instead of DELETE when possible
1011
[main] Temporary tables population is increased with multi-row inserts - 256 and 16 items per INSERT
1112
[main] PersistParameterBinding has new field RowIndex, use it for multi-row inserts if needed

Orm/Xtensive.Orm/IoC/ServiceContainer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,13 @@ public static IServiceContainer Create(Type containerType, object configuration,
227227
private static ConstructorInvoker FindConstructorInvoker(Type containerType, params Type[] argumentTypes) =>
228228
containerType.GetSingleConstructorInvokerOrDefault(argumentTypes);
229229
#else
230+
#pragma warning disable CS0612 // Type or member is obsolete
230231
private static ConstructorInfo FindConstructor(Type containerType, params Type[] argumentTypes) =>
231232
containerType.GetSingleConstructorOrDefault(argumentTypes);
233+
#pragma warning restore CS0612 // Type or member is obsolete
232234
#endif
233235

234-
#endregion
236+
#endregion
235237

236238
/// <summary>
237239
/// Creates <see cref="IServiceContainer"/> by default configuration.

Orm/Xtensive.Orm/Reflection/TypeHelper.cs

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ public int GetHashCode((Type, Type[]) obj)
4747

4848
private static readonly object EmitLock = new object();
4949
private static readonly int NullableTypeMetadataToken = WellKnownTypes.NullableOfT.MetadataToken;
50-
private static readonly int ValueTuple1 = typeof(ValueTuple<>).MetadataToken;
51-
private static readonly int ValueTuple8 = typeof(ValueTuple<,,,,,,,>).MetadataToken;
50+
private static readonly int ValueTuple1MetadataToken = typeof(ValueTuple<>).MetadataToken;
51+
private static readonly int ValueTuple8MetadataToken = typeof(ValueTuple<,,,,,,,>).MetadataToken;
5252
private static readonly Module SystemCoreLibModule = WellKnownTypes.NullableOfT.Module;
5353
private static readonly Type CompilerGeneratedAttributeType = typeof(CompilerGeneratedAttribute);
5454
private static readonly string TypeHelperNamespace = typeof(TypeHelper).Namespace;
5555

56+
#region Caches and cache items factories
5657
#if NET8_0_OR_GREATER
5758
private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInvoker> ConstructorInvokerByTypes =
58-
#else
59-
private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInfo> ConstructorInfoByTypes =
59+
new(new TypesEqualityComparer());
6060
#endif
61+
private static readonly ConcurrentDictionary<(Type, Type[]), ConstructorInfo> ConstructorInfoByTypes =
6162
new(new TypesEqualityComparer());
6263

6364
private static readonly ConcurrentDictionary<Type, Type[]> OrderedInterfaces = new();
@@ -71,16 +72,11 @@ public int GetHashCode((Type, Type[]) obj)
7172
private static readonly ConcurrentDictionary<(MethodInfo, Type), MethodInfo> GenericMethodInstances1 = new();
7273

7374
private static readonly ConcurrentDictionary<(MethodInfo, Type, Type), MethodInfo> GenericMethodInstances2 = new();
74-
7575
#if NET8_0_OR_GREATER
76-
private static readonly ConcurrentDictionary<(MethodInfo, Type), MethodInvoker> GenericMethodInvokers1 = new();
77-
private static readonly ConcurrentDictionary<(MethodInfo, Type, Type), MethodInvoker> GenericMethodInvokers2 = new();
7876

79-
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument), MethodInvoker> GenericMethodInvokerFactory1 =
80-
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument));
77+
private static readonly ConcurrentDictionary<(MethodInfo, Type), MethodInvoker> GenericMethodInvokers1 = new();
8178

82-
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2), MethodInvoker> GenericMethodInvokerFactory2 =
83-
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument1, key.typeArgument2));
79+
private static readonly ConcurrentDictionary<(MethodInfo, Type, Type), MethodInvoker> GenericMethodInvokers2 = new();
8480
#endif
8581

8682
private static readonly ConcurrentDictionary<(Type, Type), Type> GenericTypeInstances1 = new();
@@ -93,11 +89,21 @@ public int GetHashCode((Type, Type[]) obj)
9389
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2), MethodInfo> GenericMethodFactory2 =
9490
key => key.genericDefinition.MakeGenericMethod(key.typeArgument1, key.typeArgument2);
9591

96-
private static readonly Func<(Type genericDefinition, Type typeArgument), Type> GenericTypeFactory1 = key =>
97-
key.genericDefinition.MakeGenericType(key.typeArgument);
92+
private static readonly Func<(Type genericDefinition, Type typeArgument), Type> GenericTypeFactory1 =
93+
key => key.genericDefinition.MakeGenericType(key.typeArgument);
94+
95+
private static readonly Func<(Type genericDefinition, Type typeArgument1, Type typeArgument2), Type> GenericTypeFactory2 =
96+
key => key.genericDefinition.MakeGenericType(key.typeArgument1, key.typeArgument2);
97+
#if NET8_0_OR_GREATER
98+
99+
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument), MethodInvoker> GenericMethodInvokerFactory1 =
100+
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument));
101+
102+
private static readonly Func<(MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2), MethodInvoker> GenericMethodInvokerFactory2 =
103+
key => MethodInvoker.Create(key.genericDefinition.MakeGenericMethod(key.typeArgument1, key.typeArgument2));
104+
#endif
98105

99-
private static readonly Func<(Type genericDefinition, Type typeArgument1, Type typeArgument2), Type> GenericTypeFactory2 = key =>
100-
key.genericDefinition.MakeGenericType(key.typeArgument1, key.typeArgument2);
106+
#endregion
101107

102108
private static int createDummyTypeNumber = 0;
103109
private static AssemblyBuilder assemblyBuilder;
@@ -645,34 +651,50 @@ public static object Activate(this Type type, Type[] genericArguments, params ob
645651
}
646652
}
647653

654+
#if NET8_0_OR_GREATER
648655
/// <summary>
649-
/// Gets the public constructor of type <paramref name="type"/>
656+
/// Gets <see cref="ConstructorInvoker"/> of the public constructor of type <paramref name="type"/>
650657
/// accepting specified <paramref name="argumentTypes"/>.
651658
/// </summary>
652659
/// <param name="type">The type to get the constructor for.</param>
653660
/// <param name="argumentTypes">The arguments.</param>
654661
/// <returns>
655-
/// Appropriate constructor, if a single match is found;
662+
/// Appropriate constructor invoker, if a single match is found;
656663
/// otherwise throws <see cref="InvalidOperationException"/>.
657664
/// </returns>
658665
/// <exception cref="InvalidOperationException">
659666
/// The <paramref name="type"/> has no constructors suitable for <paramref name="argumentTypes"/>
660667
/// -or- more than one such constructor.
661668
/// </exception>
662-
#if NET8_0_OR_GREATER
663-
public static ConstructorInvoker GetSingleConstructorInvoker(this Type type, Type[] argumentTypes) =>
669+
internal static ConstructorInvoker GetSingleConstructorInvoker(this Type type, Type[] argumentTypes) =>
664670
ConstructorInvokerByTypes.GetOrAdd((type, argumentTypes),
665671
static t => ConstructorExtractor(t) is ConstructorInfo ctor
666672
? ConstructorInvoker.Create(ctor)
667673
: throw new InvalidOperationException(Strings.ExGivenTypeHasNoOrMoreThanOneCtorWithGivenParameters));
668-
#else
674+
675+
#endif
676+
/// <summary>
677+
/// Gets the public constructor of type <paramref name="type"/>
678+
/// accepting specified <paramref name="argumentTypes"/>.
679+
/// </summary>
680+
/// <param name="type">The type to get the constructor for.</param>
681+
/// <param name="argumentTypes">The arguments.</param>
682+
/// <returns>
683+
/// Appropriate constructor, if a single match is found;
684+
/// otherwise throws <see cref="InvalidOperationException"/>.
685+
/// </returns>
686+
/// <exception cref="InvalidOperationException">
687+
/// The <paramref name="type"/> has no constructors suitable for <paramref name="argumentTypes"/>
688+
/// -or- more than one such constructor.
689+
/// </exception>
690+
[Obsolete]// obsolete to safely make it internal later on or delete
669691
public static ConstructorInfo GetSingleConstructor(this Type type, Type[] argumentTypes) =>
670692
ConstructorInfoByTypes.GetOrAdd((type, argumentTypes), ConstructorExtractor)
671693
?? throw new InvalidOperationException(Strings.ExGivenTypeHasNoOrMoreThanOneCtorWithGivenParameters);
672-
#endif
673694

695+
#if NET8_0_OR_GREATER
674696
/// <summary>
675-
/// Gets the public constructor of type <paramref name="type"/>
697+
/// Gets <see cref="ConstructorInvoker"/> of the public constructor of type <paramref name="type"/>
676698
/// accepting specified <paramref name="argumentTypes"/>.
677699
/// </summary>
678700
/// <param name="type">The type to get the constructor for.</param>
@@ -682,14 +704,25 @@ public static ConstructorInfo GetSingleConstructor(this Type type, Type[] argume
682704
/// otherwise, <see langword="null"/>.
683705
/// </returns>
684706
[CanBeNull]
685-
#if NET8_0_OR_GREATER
686-
public static ConstructorInvoker GetSingleConstructorInvokerOrDefault(this Type type, Type[] argumentTypes) =>
707+
internal static ConstructorInvoker GetSingleConstructorInvokerOrDefault(this Type type, Type[] argumentTypes) =>
687708
ConstructorInvokerByTypes.GetOrAdd((type, argumentTypes),
688709
static t => ConstructorExtractor(t) is ConstructorInfo ctor ? ConstructorInvoker.Create(ctor) : null);
689-
#else
710+
711+
#endif
712+
/// <summary>
713+
/// Gets the public constructor of type <paramref name="type"/>
714+
/// accepting specified <paramref name="argumentTypes"/>.
715+
/// </summary>
716+
/// <param name="type">The type to get the constructor for.</param>
717+
/// <param name="argumentTypes">The arguments.</param>
718+
/// <returns>
719+
/// Appropriate constructor, if a single match is found;
720+
/// otherwise, <see langword="null"/>.
721+
/// </returns>
722+
[CanBeNull]
723+
[Obsolete]// obsolete to safely make it internal later on
690724
public static ConstructorInfo GetSingleConstructorOrDefault(this Type type, Type[] argumentTypes) =>
691725
ConstructorInfoByTypes.GetOrAdd((type, argumentTypes), ConstructorExtractor);
692-
#endif
693726

694727
private static readonly Func<(Type, Type[]), ConstructorInfo> ConstructorExtractor = t => {
695728
(var type, var argumentTypes) = t;
@@ -943,23 +976,68 @@ public static bool IsGenericMethodSpecificationOf(this MethodInfo method, Method
943976
|| method.Module == genericMethodDefinition.Module)
944977
&& method.IsGenericMethod && genericMethodDefinition.IsGenericMethodDefinition;
945978

979+
/// <summary>
980+
/// Makes generic <see cref="MethodInfo"/> for given definition and type argument
981+
/// or returns already existing instance from cache.
982+
/// </summary>
983+
/// <param name="genericDefinition">Generic definition of method.</param>
984+
/// <param name="typeArgument">Type argument for final generic method.</param>
985+
/// <returns>Newly created instance or already existing one.</returns>
946986
public static MethodInfo CachedMakeGenericMethod(this MethodInfo genericDefinition, Type typeArgument) =>
947987
GenericMethodInstances1.GetOrAdd((genericDefinition, typeArgument), GenericMethodFactory1);
948988

989+
/// <summary>
990+
/// Makes generic <see cref="MethodInfo"/> for given definition and type arguments
991+
/// or returns already existing instance from cache.
992+
/// </summary>
993+
/// <param name="genericDefinition">Generic definition of method.</param>
994+
/// <param name="typeArgument1">First type argument for final generic method.</param>
995+
/// <param name="typeArgument2">Second type argument for final generic method.</param>
996+
/// <returns>Newly created instance or already existing one.</returns>
949997
public static MethodInfo CachedMakeGenericMethod(this MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2) =>
950998
GenericMethodInstances2.GetOrAdd((genericDefinition, typeArgument1, typeArgument2), GenericMethodFactory2);
951999

9521000
#if NET8_0_OR_GREATER
1001+
/// <summary>
1002+
/// Makes <see cref="MethodInvoker"/> for generic <see cref="MethodInfo"/> for given definition and type argument
1003+
/// or returns already existing instance from cache.
1004+
/// </summary>
1005+
/// <param name="genericDefinition">Generic definition of method.</param>
1006+
/// <param name="typeArgument">Type argument for final generic method.</param>
1007+
/// <returns>Newly created instance or already existing one.</returns>
9531008
public static MethodInvoker CachedMakeGenericMethodInvoker(this MethodInfo genericDefinition, Type typeArgument) =>
9541009
GenericMethodInvokers1.GetOrAdd((genericDefinition, typeArgument), GenericMethodInvokerFactory1);
9551010

1011+
/// <summary>
1012+
/// Makes <see cref="MethodInvoker"/> for generic <see cref="MethodInfo"/> for given definition and type arguments
1013+
/// or returns already existing instance from cache.
1014+
/// </summary>
1015+
/// <param name="genericDefinition">Generic definition of method.</param>
1016+
/// <param name="typeArgument1">First type argument for final generic method.</param>
1017+
/// <param name="typeArgument2">Second type argument for final generic method.</param>
1018+
/// <returns>Newly created instance or already existing one.</returns>
9561019
public static MethodInvoker CachedMakeGenericMethodInvoker(this MethodInfo genericDefinition, Type typeArgument1, Type typeArgument2) =>
9571020
GenericMethodInvokers2.GetOrAdd((genericDefinition, typeArgument1, typeArgument2), GenericMethodInvokerFactory2);
9581021
#endif
9591022

1023+
/// <summary>
1024+
/// Makes generic type of given type definition and type argument
1025+
/// or returns already existing instance from cache.
1026+
/// </summary>
1027+
/// <param name="genericDefinition">Generic type definition.</param>
1028+
/// <param name="typeArgument">Type argument for final generic type.</param>
1029+
/// <returns>Newly created instance or already existing one.</returns>
9601030
public static Type CachedMakeGenericType(this Type genericDefinition, Type typeArgument) =>
9611031
GenericTypeInstances1.GetOrAdd((genericDefinition, typeArgument), GenericTypeFactory1);
9621032

1033+
/// <summary>
1034+
/// Makes generic type of given type definition and type argument
1035+
/// or returns already existing instance from cache.
1036+
/// </summary>
1037+
/// <param name="genericDefinition">Generic type definition.</param>
1038+
/// <param name="typeArgument1">First type argument for final generic type.</param>
1039+
/// <param name="typeArgument2">Second type argument for final generic type.</param>
1040+
/// <returns>Newly created instance or already existing one.</returns>
9631041
public static Type CachedMakeGenericType(this Type genericDefinition, Type typeArgument1, Type typeArgument2) =>
9641042
GenericTypeInstances2.GetOrAdd((genericDefinition, typeArgument1, typeArgument2), GenericTypeFactory2);
9651043

@@ -1179,7 +1257,7 @@ internal static bool IsValueTuple(this Type type)
11791257
// this stands on the theory that tokens for all generic versions of ValueTuple
11801258
// go one after another.
11811259
var currentToken = type.MetadataToken;
1182-
return ((currentToken >= ValueTuple1) && currentToken <= ValueTuple8)
1260+
return ((currentToken >= ValueTuple1MetadataToken) && currentToken <= ValueTuple8MetadataToken)
11831261
&& ReferenceEquals(type.Module, SystemCoreLibModule);
11841262
}
11851263

0 commit comments

Comments
 (0)