/// <summary> /// Smart emission for Call methods. /// </summary> /// <param name="il">Self.</param> /// <param name="methodInfo">Static, virtual, instance method.</param> /// <param name="funcs">List of methods to prepare parameters in stack.</param> /// <returns>Self.</returns> public static ILEmitter CallMethod( this ILEmitter il, MethodInfo methodInfo, params ILEmitterFunc[] funcs) { var owner = methodInfo.DeclaringType; if (owner == typeof(ValueType)) { owner = methodInfo.ReflectedType; // todo: 0. test } if (owner == null) { throw new InvalidOperationException( $"It's not expected that {methodInfo.DisplayName()} doesn't have a declaring type."); } if (methodInfo.IsGenericMethodDefinition) { throw new InvalidOperationException( $"Generic method {methodInfo.DisplayName()} is not initialized."); } // if the method belongs to Enum type, them it should be called as virtual and with constrained prefix // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.constrained //var isEnum = owner.IsAssignableFrom(typeof(Enum)); //if (isEnum) { // Constrained(owner); // todo: 0. test //} return(methodInfo.IsStatic || owner.IsValueType || owner.IsSealed || !methodInfo.IsVirtual // todo: 0. test ? il.Call(methodInfo, funcs) : il.Callvirt(methodInfo, funcs)); }