<PackageReference Include="NUnit" Version="3.11.0" />

GenericMethodHelper

public class GenericMethodHelper
GenericMethodHelper is able to deduce the Type arguments for a generic method from the actual arguments provided.
using System; using System.Reflection; namespace NUnit.Framework.Internal { public class GenericMethodHelper { private static class ConflictingTypesMarkerClass { } private static readonly Type ConflictingTypesMarker = typeof(ConflictingTypesMarkerClass); private MethodInfo Method { get; } private Type[] TypeParms { get; } private Type[] TypeArgs { get; } private Type[] ParmTypes { get; } public GenericMethodHelper(MethodInfo method) { Guard.ArgumentValid(method.IsGenericMethod, "Specified method must be generic", "method"); Method = method; TypeParms = Method.GetGenericArguments(); TypeArgs = new Type[TypeParms.Length]; ParameterInfo[] parameters = Method.GetParameters(); ParmTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { ParmTypes[i] = parameters[i].ParameterType; } } public bool TryGetTypeArguments(object[] argList, out Type[] typeArguments) { Guard.ArgumentValid(argList.Length == ParmTypes.Length, "Supplied arguments do not match required method parameters", "argList"); for (int i = 0; i < ParmTypes.Length; i++) { object obj = argList[i]; if (obj != null) { Type type = obj.GetType(); TryApplyArgType(ParmTypes[i], type); } } Type[] typeArgs = TypeArgs; foreach (Type left in typeArgs) { if (left == (Type)null || left == ConflictingTypesMarker) { typeArguments = null; return false; } } typeArguments = TypeArgs; return true; } private void TryApplyArgType(Type parmType, Type argType) { if (parmType.IsGenericParameter) ApplyArgType(parmType, argType); else if (parmType.GetTypeInfo().ContainsGenericParameters) { Type[] genericArguments = parmType.GetGenericArguments(); if (argType.HasElementType) ApplyArgType(genericArguments[0], argType.GetElementType()); else if (argType.GetTypeInfo().IsGenericType && IsAssignableToGenericType(argType, parmType)) { Type[] genericArguments2 = argType.GetGenericArguments(); if (genericArguments2.Length == genericArguments.Length) { for (int i = 0; i < genericArguments.Length; i++) { TryApplyArgType(genericArguments[i], genericArguments2[i]); } } } } } private void ApplyArgType(Type parmType, Type argType) { int genericParameterPosition = parmType.GenericParameterPosition; if (!TypeHelper.TryGetBestCommonType(TypeArgs[genericParameterPosition], argType, out TypeArgs[genericParameterPosition])) TypeArgs[genericParameterPosition] = ConflictingTypesMarker; } private bool IsAssignableToGenericType(Type givenType, Type genericType) { Type[] interfaces = givenType.GetInterfaces(); foreach (Type type in interfaces) { if (type.GetTypeInfo().IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition.Name == genericType.Name && genericTypeDefinition.Namespace == genericType.Namespace) return true; } } if (givenType.GetTypeInfo().IsGenericType) { Type genericTypeDefinition2 = givenType.GetGenericTypeDefinition(); if (genericTypeDefinition2.Name == genericType.Name && genericTypeDefinition2.Namespace == genericType.Namespace) return true; } Type baseType = givenType.GetTypeInfo().BaseType; if (baseType == (Type)null) return false; return IsAssignableToGenericType(baseType, genericType); } } }