/// <summary> /// Resolves an indexer property from a type by its argument. /// </summary> public static MethodWrapper ResolveIndexer(Type type, Type idxType, bool isGetter) { if (type is TypeBuilder) { throw new NotSupportedException(); } try { var indexer = resolveIndexerProperty(type, idxType, isGetter, p => p); return(new MethodWrapper(indexer)); } catch (NotSupportedException) { if (!type.IsGenericType) { throw; } var genType = type.GetGenericTypeDefinition(); var indexer = resolveIndexerProperty(genType, idxType, isGetter, p => GenericHelper.ApplyGenericArguments(p, type)); var declType = resolveActualDeclaringType(type, indexer.DeclaringType); return(new MethodWrapper { Type = type, MethodInfo = getMethodVersionForType(declType, indexer), IsStatic = false, IsVirtual = indexer.IsVirtual, ArgumentTypes = indexer.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, type)).ToArray(), ReturnType = GenericHelper.ApplyGenericArguments(indexer.ReturnType, type) }); } }
/// <summary> /// Resolves a group of methods by name. /// Only non-generic methods are returned! /// </summary> public static IEnumerable <MethodWrapper> ResolveMethodGroup(Type type, string name) { try { return(getMethodsByName(type, name).Where(m => !m.IsGenericMethod).Select(m => new MethodWrapper(m))); } catch (NotSupportedException) { if (!type.IsGenericType) { throw; } var genType = type.GetGenericTypeDefinition(); var genericMethods = getMethodsByName(genType, name).Where(m => !m.IsGenericMethod).ToArray(); return(genericMethods.Select( m => { var declType = resolveActualDeclaringType(type, m.DeclaringType); return new MethodWrapper { Name = name, Type = type, MethodInfo = getMethodVersionForType(declType, m), IsStatic = m.IsStatic, IsVirtual = m.IsVirtual, ArgumentTypes = m.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, declType)).ToArray(), ReturnType = GenericHelper.ApplyGenericArguments(m.ReturnType, declType) }; } )); } }
/// <summary> /// Resolves a property from a type by its name. /// </summary> public static PropertyWrapper ResolveProperty(Type type, string name) { try { var pty = type.GetProperty(name); if (pty == null) { throw new KeyNotFoundException(); } var getter = pty.GetGetMethod(); var setter = pty.GetSetMethod(); return(new PropertyWrapper { Name = name, Type = type, Getter = getter, Setter = setter, IsStatic = (getter ?? setter).IsStatic, PropertyType = pty.PropertyType, IsVirtual = (getter ?? setter).IsVirtual }); } catch (NotSupportedException) { if (!type.IsGenericType) { throw new KeyNotFoundException(); } var genType = type.GetGenericTypeDefinition(); var genPty = genType.GetProperty(name); if (genPty == null) { throw new KeyNotFoundException(); } var getter = genPty.GetGetMethod(); var setter = genPty.GetSetMethod(); var declType = ResolveActualDeclaringType(type, genPty.DeclaringType); return(new PropertyWrapper { Name = name, Type = type, Getter = GetMethodVersionForType(declType, getter), Setter = GetMethodVersionForType(declType, setter), IsStatic = (getter ?? setter).IsStatic, PropertyType = GenericHelper.ApplyGenericArguments(genPty.PropertyType, type), }); } }
/// <summary> /// Resolves an event by its name. /// </summary> public static EventWrapper ResolveEvent(Type type, string name) { try { var evt = type.GetEvent(name); if (evt == null) { throw new KeyNotFoundException(); } return(new EventWrapper { Name = name, Type = type, IsStatic = evt.GetRemoveMethod().IsStatic, AddMethod = evt.GetAddMethod(), RemoveMethod = evt.GetRemoveMethod(), EventHandlerType = evt.EventHandlerType }); } catch (NotSupportedException) { if (!type.IsGenericType) { throw new KeyNotFoundException(); } var genType = type.GetGenericTypeDefinition(); var genEvt = genType.GetEvent(name); if (genEvt == null) { throw new KeyNotFoundException(); } var adder = genEvt.GetAddMethod(); var remover = genEvt.GetRemoveMethod(); var declType = resolveActualDeclaringType(type, genEvt.DeclaringType); return(new EventWrapper { Name = name, Type = type, AddMethod = getMethodVersionForType(declType, adder), RemoveMethod = getMethodVersionForType(declType, remover), IsStatic = adder.IsStatic, EventHandlerType = GenericHelper.ApplyGenericArguments(genEvt.EventHandlerType, type) }); } }
/// <summary> /// Get interfaces of a possibly generic type. /// </summary> public static Type[] ResolveInterfaces(this Type type) { if (m_InterfaceCache.ContainsKey(type)) { return(m_InterfaceCache[type].ToArray()); } Type[] ifaces; try { ifaces = type.GetInterfaces(); } catch (NotSupportedException) { if (type.IsGenericType) { ifaces = type.GetGenericTypeDefinition().GetInterfaces(); for (var idx = 0; idx < ifaces.Length; idx++) { var curr = ifaces[idx]; if (curr.IsGenericType) { ifaces[idx] = GenericHelper.ApplyGenericArguments(curr, type); } } } else if (type.IsArray) { // replace interfaces of any array with element type var elem = type.GetElementType(); ifaces = typeof(int[]).GetInterfaces(); for (var idx = 0; idx < ifaces.Length; idx++) { var curr = ifaces[idx]; if (curr.IsGenericType) { ifaces[idx] = curr.GetGenericTypeDefinition().MakeGenericType(elem); } } } // just a built-in type : no interfaces else { ifaces = Type.EmptyTypes; } } m_InterfaceCache.Add(type, ifaces); return(ifaces.ToArray()); }
/// <summary> /// Resolves a field from a type by its name. /// </summary> public static FieldWrapper ResolveField(Type type, string name) { try { var field = type.GetField(name); if (field == null) { throw new KeyNotFoundException(); } return(new FieldWrapper { Name = name, Type = type, FieldInfo = field, IsStatic = field.IsStatic, IsLiteral = field.IsLiteral, FieldType = field.FieldType }); } catch (NotSupportedException) { if (!type.IsGenericType) { throw new KeyNotFoundException(); } var genType = type.GetGenericTypeDefinition(); var genField = genType.GetField(name); if (genField == null) { throw new KeyNotFoundException(); } return(new FieldWrapper { Name = name, Type = type, FieldInfo = TypeBuilder.GetField(type, genField), IsStatic = genField.IsStatic, IsLiteral = genField.IsLiteral, FieldType = GenericHelper.ApplyGenericArguments(genField.FieldType, type) }); } }
/// <summary> /// Resolves an extension method by arguments. /// </summary> public static MethodWrapper ResolveExtensionMethod(ExtensionMethodResolver resolver, Type type, string name, Type[] argTypes, Type[] hints, LambdaResolver lambdaResolver) { var method = resolver.ResolveExtensionMethod(type, name, argTypes); var args = method.GetParameters(); var info = new MethodWrapper { Name = name, Type = method.DeclaringType, MethodInfo = method, IsStatic = true, IsVirtual = false, ReturnType = method.ReturnType, ArgumentTypes = args.Select(p => p.ParameterType).ToArray(), IsPartiallyApplied = IsPartiallyApplied(argTypes), IsVariadic = IsVariadic(method), }; if (method.IsGenericMethod) { var expectedTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); var genericDefs = method.GetGenericArguments(); var extMethodArgs = argTypes.ToList(); extMethodArgs.Insert(0, type); var genericValues = GenericHelper.ResolveMethodGenericsByArgs( expectedTypes, extMethodArgs.ToArray(), genericDefs, hints, lambdaResolver ); info.GenericArguments = genericValues; info.MethodInfo = info.MethodInfo.MakeGenericMethod(genericValues); info.ReturnType = GenericHelper.ApplyGenericArguments(info.ReturnType, genericDefs, genericValues); info.ArgumentTypes = expectedTypes.Select(t => GenericHelper.ApplyGenericArguments(t, genericDefs, genericValues)).ToArray(); } else if (hints != null) { error(CompilerMessages.GenericArgsToNonGenericMethod, name); } return(info); }
/// <summary> /// Resolves a constructor from a type by the list of arguments. /// </summary> public static ConstructorWrapper ResolveConstructor(Type type, Type[] argTypes) { try { var ctor = ResolveMethodByArgs( type.GetConstructors(), c => c.GetParameters().Select(p => p.ParameterType).ToArray(), IsVariadic, argTypes ); return(new ConstructorWrapper { Type = type, ConstructorInfo = ctor.Method, ArgumentTypes = ctor.ArgumentTypes, IsPartiallyApplied = IsPartiallyApplied(argTypes), IsVariadic = IsVariadic(ctor.Method) }); } catch (NotSupportedException) { if (!type.IsGenericType) { throw new KeyNotFoundException(); } var genType = type.GetGenericTypeDefinition(); var genCtor = ResolveMethodByArgs( genType.GetConstructors(), c => c.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, type)).ToArray(), IsVariadic, argTypes ); return(new ConstructorWrapper { Type = type, ConstructorInfo = TypeBuilder.GetConstructor(type, genCtor.Method), ArgumentTypes = genCtor.ArgumentTypes, IsPartiallyApplied = IsPartiallyApplied(argTypes), IsVariadic = IsVariadic(genCtor.Method) }); } }
/// <summary> /// Resolves a method by its name and argument types. If generic arguments are passed, they are also applied. /// Generic arguments whose values can be inferred from argument types can be skipped. /// </summary> public static MethodWrapper ResolveMethod(Type type, string name, Type[] argTypes, Type[] hints, LambdaResolver lambdaResolver) { var mw = new MethodWrapper { Name = name, Type = type }; try { var method = ResolveMethodByArgs( getMethodsByName(type, name), m => m.GetParameters().Select(p => p.ParameterType).ToArray(), IsVariadic, argTypes ); var mInfo = method.Method; if (mInfo.IsGenericMethod) { var genericDefs = mInfo.GetGenericArguments(); var genericValues = GenericHelper.ResolveMethodGenericsByArgs(method.ArgumentTypes, argTypes, genericDefs, hints); mInfo = mInfo.MakeGenericMethod(genericValues); mw.GenericArguments = genericValues; } else if (hints != null) { error(CompilerMessages.GenericArgsToNonGenericMethod, name); } mw.MethodInfo = mInfo; mw.IsStatic = mInfo.IsStatic; mw.IsVirtual = mInfo.IsVirtual; mw.ArgumentTypes = method.ArgumentTypes; mw.ReturnType = mInfo.ReturnType; mw.IsPartiallyApplied = IsPartiallyApplied(argTypes); mw.IsVariadic = IsVariadic(mInfo); return(mw); } catch (NotSupportedException) { if (!type.IsGenericType) { throw new KeyNotFoundException(); } var genType = type.GetGenericTypeDefinition(); var genMethod = ResolveMethodByArgs( getMethodsByName(genType, name), m => m.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, type, false)).ToArray(), IsVariadic, argTypes ); var mInfoOriginal = genMethod.Method; var declType = resolveActualDeclaringType(type, mInfoOriginal.DeclaringType); var mInfo = getMethodVersionForType(declType, mInfoOriginal); if (mInfoOriginal.IsGenericMethod) { var genericDefs = mInfoOriginal.GetGenericArguments(); var genericValues = GenericHelper.ResolveMethodGenericsByArgs(genMethod.ArgumentTypes, argTypes, genericDefs, hints, lambdaResolver); mInfo = mInfo.MakeGenericMethod(genericValues); var totalGenericDefs = genericDefs.Union(genType.GetGenericTypeDefinition().GetGenericArguments()).ToArray(); var totalGenericValues = genericValues.Union(type.GetGenericArguments()).ToArray(); mw.GenericArguments = genericValues; mw.ReturnType = GenericHelper.ApplyGenericArguments(mInfoOriginal.ReturnType, totalGenericDefs, totalGenericValues); mw.ArgumentTypes = mInfoOriginal.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, totalGenericDefs, totalGenericValues)).ToArray(); } else { if (hints != null) { error(CompilerMessages.GenericArgsToNonGenericMethod, name); } mw.ArgumentTypes = mInfoOriginal.GetParameters().Select(p => GenericHelper.ApplyGenericArguments(p.ParameterType, type)).ToArray(); mw.ReturnType = GenericHelper.ApplyGenericArguments(mInfoOriginal.ReturnType, type, false); } mw.MethodInfo = mInfo; mw.IsStatic = mInfoOriginal.IsStatic; mw.IsVirtual = mInfoOriginal.IsVirtual; mw.IsPartiallyApplied = IsPartiallyApplied(argTypes); mw.IsVariadic = IsVariadic(mInfoOriginal); } return(mw); }