private object InvokeImpl(object? arg1, object? arg2, object? arg3, object? arg4)
{
- if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers)) != 0)
+ if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers | InvocationFlags.NoConstructorInvoke)) != 0)
{
_method.ThrowNoInvokeException();
}
{
// This is useful for calling a constructor on an already-initialized object
// such as created from RuntimeHelpers.GetUninitializedObject(Type).
- return new MethodInvoker(rci);
+ MethodInvoker invoker = new MethodInvoker(rci);
+
+ // Use the interpreted version to avoid having to generate a new method that doesn't allocate.
+ invoker._strategy = GetStrategyForUsingInterpreted();
+
+ return invoker;
}
throw new ArgumentException(SR.Argument_MustBeRuntimeMethod, nameof(method));
private object? InvokeImpl(object? obj, object? arg1, object? arg2, object? arg3, object? arg4)
{
- if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers)) != 0)
+ if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers | InvocationFlags.NoConstructorInvoke)) != 0)
{
ThrowForBadInvocationFlags();
}
{
if (LocalAppContextSwitches.ForceInterpretedInvoke && !LocalAppContextSwitches.ForceEmitInvoke)
{
- // Always use the native invoke; useful for testing.
- strategy = InvokerStrategy.StrategyDetermined_Obj4Args | InvokerStrategy.StrategyDetermined_ObjSpanArgs | InvokerStrategy.StrategyDetermined_RefArgs;
+ // Always use the native interpreted invoke.
+ // Useful for testing, to avoid startup overhead of emit, or for calling a ctor on already initialized object.
+ strategy = GetStrategyForUsingInterpreted();
}
else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke)
{
// Always use emit invoke (if IsDynamicCodeSupported == true); useful for testing.
- strategy = InvokerStrategy.HasBeenInvoked_Obj4Args | InvokerStrategy.HasBeenInvoked_ObjSpanArgs | InvokerStrategy.HasBeenInvoked_RefArgs;
+ strategy = GetStrategyForUsingEmit();
}
else
{
}
}
+ internal static InvokerStrategy GetStrategyForUsingInterpreted()
+ {
+ // This causes the default strategy, which is interpreted, to always be used.
+ return InvokerStrategy.StrategyDetermined_Obj4Args | InvokerStrategy.StrategyDetermined_ObjSpanArgs | InvokerStrategy.StrategyDetermined_RefArgs;
+ }
+
+ private static InvokerStrategy GetStrategyForUsingEmit()
+ {
+ // This causes the emit strategy, if supported, to be used on the first call as well as subsequent calls.
+ return InvokerStrategy.HasBeenInvoked_Obj4Args | InvokerStrategy.HasBeenInvoked_ObjSpanArgs | InvokerStrategy.HasBeenInvoked_RefArgs;
+ }
+
/// <summary>
/// Confirm member invocation has an instance and is of the correct type
/// </summary>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Linq;
+using Xunit;
+
+namespace System.Reflection.Tests
+{
+ /// <summary>
+ /// These tests are shared with ConstructorInfo.Invoke and ConstructorInvoker.Invoke by using
+ /// the abstract Invoke(...) methods below.
+ /// </summary>
+ public abstract class ConstructorCommonTests
+ {
+ public abstract object Invoke(ConstructorInfo constructorInfo, object?[]? parameters);
+
+ protected abstract bool IsExceptionWrapped { get; }
+
+ /// <summary>
+ /// Invoke constructor on an existing instance. Should return null.
+ /// </summary>
+ public abstract object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters);
+
+ public static ConstructorInfo[] GetConstructors(Type type)
+ {
+ return type.GetTypeInfo().DeclaredConstructors.ToArray();
+ }
+
+ [Fact]
+ public void SimpleInvoke()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ Assert.Equal(3, constructors.Length);
+ ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[0], null);
+ Assert.NotNull(obj);
+ }
+
+ [Fact]
+ [ActiveIssue("https://github.com/mono/mono/issues/15024", TestRuntimes.Mono)]
+ public void Invoke_StaticConstructor_ThrowsMemberAccessException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor));
+ Assert.Equal(1, constructors.Length);
+ Assert.Throws<MemberAccessException>(() => Invoke(constructors[0], new object[0]));
+ }
+
+ [Fact]
+ public void Invoke_OneDimensionalArray()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(object[]));
+ int[] arraylength = { 1, 2, 99, 65535 };
+
+ // Try to invoke Array ctors with different lengths
+ foreach (int length in arraylength)
+ {
+ // Create big Array with elements
+ object[] arr = (object[])Invoke(constructors[0], new object[] { length });
+ Assert.Equal(arr.Length, length);
+ }
+ }
+
+ [Fact]
+ public void Invoke_OneDimensionalArray_NegativeLengths_ThrowsOverflowException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(object[]));
+ int[] arraylength = new int[] { -1, -2, -99 };
+ // Try to invoke Array ctors with different lengths
+ foreach (int length in arraylength)
+ {
+ // Create big Array with elements
+ if (IsExceptionWrapped)
+ {
+ Exception ex = Assert.Throws<TargetInvocationException>(() => Invoke(constructors[0], new object[] { length }));
+ Assert.IsType<OverflowException>(ex.InnerException);
+ }
+ else
+ {
+ Assert.Throws<OverflowException>(() => Invoke(constructors[0], new object[] { length }));
+ }
+ }
+ }
+
+ [Fact]
+ public void Invoke_OneParameter()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[1], new object[] { 100 });
+ Assert.Equal(100, obj.intValue);
+ }
+
+ [Fact]
+ public void Invoke_TwoParameters()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[2], new object[] { 101, "hello" });
+ Assert.Equal(101, obj.intValue);
+ Assert.Equal("hello", obj.stringValue);
+ }
+
+ [Fact]
+ public void Invoke_NoParameters_ThowsTargetParameterCountException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ Assert.Throws<TargetParameterCountException>(() => Invoke(constructors[2], new object[0]));
+ }
+
+ [Fact]
+ public void Invoke_ParameterMismatch_ThrowsTargetParameterCountException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ Assert.Throws<TargetParameterCountException>(() => (ClassWith3Constructors)Invoke(constructors[2], new object[] { 121 }));
+ }
+
+ [Fact]
+ public void Invoke_ParameterWrongType_ThrowsArgumentException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ AssertExtensions.Throws<ArgumentException>(null, () => (ClassWith3Constructors)Invoke(constructors[1], new object[] { "hello" }));
+ }
+
+ [Fact]
+ public void Invoke_ExistingInstance()
+ {
+ // Should not produce a second object.
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ ClassWith3Constructors obj1 = new ClassWith3Constructors(100, "hello");
+ ClassWith3Constructors obj2 = (ClassWith3Constructors)Invoke(constructors[2], obj1, new object[] { 999, "initialized" });
+ Assert.Null(obj2);
+ Assert.Equal(999, obj1.intValue);
+ Assert.Equal("initialized", obj1.stringValue);
+ }
+
+ [Fact]
+ public void Invoke_NullForObj()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
+ Assert.Throws<TargetException>(() => Invoke(constructors[2], obj: null, new object[] { 999, "initialized" }));
+ }
+
+ [Fact]
+ [ActiveIssue("https://github.com/mono/mono/issues/15026", TestRuntimes.Mono)]
+ public void Invoke_AbstractClass_ThrowsMemberAccessException()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoAbstractBase));
+ Assert.Throws<MemberAccessException>(() => (ConstructorInfoAbstractBase)Invoke(constructors[0], new object[0]));
+ }
+
+ [Fact]
+ public void Invoke_SubClass()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoDerived));
+ ConstructorInfoDerived obj = null;
+ obj = (ConstructorInfoDerived)Invoke(constructors[0], new object[] { });
+ Assert.NotNull(obj);
+ }
+
+ [Fact]
+ public void Invoke_Struct()
+ {
+ ConstructorInfo[] constructors = GetConstructors(typeof(StructWith1Constructor));
+ StructWith1Constructor obj;
+ obj = (StructWith1Constructor)Invoke(constructors[0], new object[] { 1, 2 });
+ Assert.Equal(1, obj.x);
+ Assert.Equal(2, obj.y);
+ }
+ }
+}
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
-using System.Linq;
using Xunit;
#pragma warning disable 0414
namespace System.Reflection.Tests
{
- public class ConstructorInfoTests
+ /// <summary>
+ /// These tests use the shared tests from the base class with ConstructorInfo.Invoke.
+ /// </summary>
+ public sealed class ConstructorInfoTests : ConstructorCommonTests
{
+ public override object Invoke(ConstructorInfo constructorInfo, object?[]? parameters)
+ {
+ return constructorInfo.Invoke(parameters);
+ }
+
+ public override object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters)
+ {
+ return constructorInfo.Invoke(obj, parameters);
+ }
+
+ protected override bool IsExceptionWrapped => true;
+
[Fact]
public void ConstructorName()
{
}
}
- [Fact]
- public void Invoke()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- Assert.Equal(3, constructors.Length);
- ClassWith3Constructors obj = (ClassWith3Constructors)constructors[0].Invoke(null);
- Assert.NotNull(obj);
- }
-
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsInvokingStaticConstructorsSupported))]
public void Invoke_StaticConstructor_NullObject_NullParameters()
{
}
[Fact]
- [ActiveIssue("https://github.com/mono/mono/issues/15024", TestRuntimes.Mono)]
- public void Invoke_StaticConstructor_ThrowsMemberAccessException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor));
- Assert.Equal(1, constructors.Length);
- Assert.Throws<MemberAccessException>(() => constructors[0].Invoke(new object[0]));
- }
-
- [Fact]
- public void Invoke_OneDimensionalArray()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(object[]));
- int[] arraylength = { 1, 2, 99, 65535 };
-
- // Try to invoke Array ctors with different lengths
- foreach (int length in arraylength)
- {
- // Create big Array with elements
- object[] arr = (object[])constructors[0].Invoke(new object[] { length });
- Assert.Equal(arr.Length, length);
- }
- }
-
- [Fact]
- public void Invoke_OneDimensionalArray_NegativeLengths_ThrowsOverflowException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(object[]));
- int[] arraylength = new int[] { -1, -2, -99 };
- // Try to invoke Array ctors with different lengths
- foreach (int length in arraylength)
- {
- // Create big Array with elements
- Exception ex = Assert.Throws<TargetInvocationException>(() => constructors[0].Invoke(new object[] { length }));
- Assert.IsType<OverflowException>(ex.InnerException);
- }
- }
-
- [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/67531", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public void Invoke_TwoDimensionalArray_CustomBinder_IncorrectTypeArguments()
{
}
[Fact]
- public void Invoke_OneParameter()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- ClassWith3Constructors obj = (ClassWith3Constructors)constructors[1].Invoke(new object[] { 100 });
- Assert.Equal(100, obj.intValue);
- }
-
- [Fact]
- public void Invoke_TwoParameters()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- ClassWith3Constructors obj = (ClassWith3Constructors)constructors[2].Invoke(new object[] { 101, "hello" });
- Assert.Equal(101, obj.intValue);
- Assert.Equal("hello", obj.stringValue);
- }
-
- [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/67531", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public void Invoke_TwoParameters_CustomBinder_IncorrectTypeArgument()
{
}
[Fact]
- public void Invoke_NoParameters_ThowsTargetParameterCountException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- Assert.Throws<TargetParameterCountException>(() => constructors[2].Invoke(new object[0]));
- }
-
- [Fact]
- public void Invoke_ParameterMismatch_ThrowsTargetParameterCountException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- Assert.Throws<TargetParameterCountException>(() => (ClassWith3Constructors)constructors[2].Invoke(new object[] { 121 }));
- }
-
- [Fact]
- public void Invoke_ParameterWrongType_ThrowsArgumentException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- AssertExtensions.Throws<ArgumentException>(null, () => (ClassWith3Constructors)constructors[1].Invoke(new object[] { "hello" }));
- }
-
- [Fact]
- public void Invoke_ExistingInstance()
- {
- // Should not produce a second object.
- ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
- ClassWith3Constructors obj1 = new ClassWith3Constructors(100, "hello");
- ClassWith3Constructors obj2 = (ClassWith3Constructors)constructors[2].Invoke(obj1, new object[] { 999, "initialized" });
- Assert.Null(obj2);
- Assert.Equal(999, obj1.intValue);
- Assert.Equal("initialized", obj1.stringValue);
- }
-
- [Fact]
- [ActiveIssue("https://github.com/mono/mono/issues/15026", TestRuntimes.Mono)]
- public void Invoke_AbstractClass_ThrowsMemberAccessException()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoAbstractBase));
- Assert.Throws<MemberAccessException>(() => (ConstructorInfoAbstractBase)constructors[0].Invoke(new object[0]));
- }
-
- [Fact]
- public void Invoke_SubClass()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoDerived));
- ConstructorInfoDerived obj = null;
- obj = (ConstructorInfoDerived)constructors[0].Invoke(new object[] { });
- Assert.NotNull(obj);
- }
-
- [Fact]
- public void Invoke_Struct()
- {
- ConstructorInfo[] constructors = GetConstructors(typeof(StructWith1Constructor));
- StructWith1Constructor obj;
- obj = (StructWith1Constructor)constructors[0].Invoke(new object[] { 1, 2 });
- Assert.Equal(1, obj.x);
- Assert.Equal(2, obj.y);
- }
-
- [Fact]
public void IsConstructor_ReturnsTrue()
{
ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors));
Assert.True(constructors[0].IsPublic);
}
- public static ConstructorInfo[] GetConstructors(Type type)
+ // Use this class only from the Invoke_StaticConstructorMultipleTimes method
+ public static class ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection
{
- return type.GetTypeInfo().DeclaredConstructors.ToArray();
+ public static class VisibleStatics
+ {
+ public static int s_cctorCallCount;
+ }
+
+ static ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection()
+ {
+ VisibleStatics.s_cctorCallCount++;
+ }
}
}
static ClassWithStaticConstructor() { }
}
- // Use this class only from the Invoke_StaticConstructorMultipleTimes method
- public static class ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection
- {
- public static class VisibleStatics
- {
- public static int s_cctorCallCount;
- }
-
- static ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection()
- {
- VisibleStatics.s_cctorCallCount++;
- }
- }
-
public struct StructWith1Constructor
{
public int x;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Runtime.CompilerServices;
using Xunit;
namespace System.Reflection.Tests
{
- public class ConstructorInvokerTests
+ /// <summary>
+ /// These tests use the shared tests from the base class with ConstructorInvoker.Invoke.
+ /// </summary>
+ public sealed class ConstructorInvokerTests : ConstructorCommonTests
{
+ public override object Invoke(ConstructorInfo constructorInfo, object?[]? parameters)
+ {
+ return ConstructorInvoker.Create(constructorInfo).Invoke(new Span<object>(parameters));
+ }
+
+ public override object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters)
+ {
+ return MethodInvoker.Create(constructorInfo).Invoke(obj, new Span<object>(parameters));
+ }
+
+ protected override bool IsExceptionWrapped => false;
[Fact]
public void Args_0()
}
[Fact]
- public void ExistingInstance()
+ public void Invoke_StaticConstructor_NullObject_NullParameters()
{
- ConstructorInfo ci = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes);
- TestClass tc = (TestClass)RuntimeHelpers.GetUninitializedObject(typeof(TestClass));
- Assert.Null(tc._args);
+ ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor));
+ Assert.Equal(1, constructors.Length);
- MethodInvoker invoker = MethodInvoker.Create(ci);
- object? obj = invoker.Invoke(tc);
- Assert.Equal("0", tc._args);
- Assert.Null(obj);
+ // Invoker classes do not support calling class constructors; use standard reflection for that.
+ Assert.Throws<MemberAccessException>(() => Invoke(constructors[0], null, new object[] { }));
}
private class TestClass
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Common.cs" />
+ <Compile Include="..\ConstructorCommonTests.cs" />
<Compile Include="..\ConstructorInfoTests.cs" />
+ <Compile Include="..\ConstructorInvokerTests.cs" />
+ <Compile Include="..\MethodCommonTests.cs" />
<Compile Include="..\MethodInfoTests.cs" />
+ <Compile Include="..\MethodInvokerTests.cs" />
<Compile Include="..\PropertyInfoTests.cs" />
<Compile Include="$(CommonTestPath)\System\Reflection\InvokeEmitTests.cs" />
</ItemGroup>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Common.cs" />
+ <Compile Include="..\ConstructorCommonTests.cs" />
<Compile Include="..\ConstructorInfoTests.cs" />
+ <Compile Include="..\ConstructorInvokerTests.cs" />
+ <Compile Include="..\MethodCommonTests.cs" />
<Compile Include="..\MethodInfoTests.cs" />
+ <Compile Include="..\MethodInvokerTests.cs" />
<Compile Include="..\PropertyInfoTests.cs" />
<Compile Include="$(CommonTestPath)\System\Reflection\InvokeInterpretedTests.cs" />
</ItemGroup>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Linq;
+using Xunit;
+
+namespace System.Reflection.Tests
+{
+ /// <summary>
+ /// These tests are shared with MethodInfo.Invoke and MethodInvoker.Invoke by using
+ /// the abstract Invoke(...) method below.
+ /// </summary>
+ public abstract class MethodCommonTests
+ {
+ public abstract object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters);
+
+ protected abstract bool SupportsMissing { get; }
+
+ protected static MethodInfo GetMethod(Type type, string name)
+ {
+ return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name));
+ }
+
+ [Fact]
+ public void InvokeNullableRefs()
+ {
+ object?[] args;
+
+ int? iNull = null;
+ args = new object[] { iNull };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.Null)), null, args));
+ Assert.Null(args[0]);
+ Assert.False(((int?)args[0]).HasValue);
+
+ args = new object[] { iNull };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullBoxed)), null, args));
+ Assert.Null(args[0]);
+
+ args = new object[] { iNull, 10 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValue)), null, args));
+ Assert.IsType<int>(args[0]);
+ Assert.Equal(10, (int)args[0]);
+
+ iNull = 42;
+ args = new object[] { iNull, 42 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.ValueToNull)), null, args));
+ Assert.Null(args[0]);
+
+ iNull = null;
+ args = new object[] { iNull, 10 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValueBoxed)), null, args));
+ Assert.IsType<int>(args[0]);
+ Assert.Equal(10, (int)args[0]);
+
+ static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod(
+ name, BindingFlags.Public | BindingFlags.Static)!;
+ }
+
+ [Fact]
+ public void InvokeBoxedNullableRefs()
+ {
+ object?[] args;
+
+ object? iNull = null;
+ args = new object[] { iNull };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.Null)), null, args));
+ Assert.Null(args[0]);
+
+ args = new object[] { iNull };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullBoxed)), null, args));
+ Assert.Null(args[0]);
+
+ args = new object[] { iNull, 10 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValue)), null, args));
+ Assert.IsType<int>(args[0]);
+ Assert.Equal(10, (int)args[0]);
+
+ iNull = 42;
+ args = new object[] { iNull, 42 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.ValueToNull)), null, args));
+ Assert.Null(args[0]);
+
+ iNull = null;
+ args = new object[] { iNull, 10 };
+ Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValueBoxed)), null, args));
+ Assert.IsType<int>(args[0]);
+ Assert.Equal(10, (int)args[0]);
+
+ static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod(
+ name, BindingFlags.Public | BindingFlags.Static)!;
+ }
+
+ [Fact]
+ public void InvokeEnum()
+ {
+ // Enums only need to match by primitive type.
+ Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)).
+ Invoke(null, new object[] { OtherColorsInt.Red }));
+
+ // Widening allowed
+ Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)).
+ Invoke(null, new object[] { ColorsShort.Red }));
+
+ // Narrowing not allowed
+ Assert.Throws<ArgumentException>(() => GetMethod(nameof(EnumMethods.PassColorsShort)).
+ Invoke(null, new object[] { OtherColorsInt.Red }));
+
+ static MethodInfo GetMethod(string name) => typeof(EnumMethods).GetMethod(
+ name, BindingFlags.Public | BindingFlags.Static)!;
+ }
+
+ [Fact]
+ public void InvokeNullableEnumParameterDefaultNo()
+ {
+ MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNo", BindingFlags.Static | BindingFlags.NonPublic);
+
+ Assert.Null(Invoke(method, null, new object?[] { default(object) }));
+ Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No }));
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes }));
+
+ if (SupportsMissing)
+ {
+ Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { Type.Missing }));
+ }
+ }
+
+ [Fact]
+ public void InvokeNullableEnumParameterDefaultYes()
+ {
+ MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic);
+
+ Assert.Null(Invoke(method, null, new object?[] { default(object) }));
+ Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No }));
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes }));
+
+ if (SupportsMissing)
+ {
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { Type.Missing }));
+ }
+ }
+
+ [Fact]
+ public void InvokeNonNullableEnumParameterDefaultYes()
+ {
+ MethodInfo method = typeof(EnumMethods).GetMethod("NonNullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic);
+
+ Assert.Equal(YesNo.No, Invoke(method, null, new object[] { default(object) }));
+ Assert.Equal(YesNo.No, Invoke(method, null, new object[] { YesNo.No }));
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object[] { YesNo.Yes }));
+
+ if (SupportsMissing)
+ {
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object[] { Type.Missing }));
+ }
+ }
+
+ [Fact]
+ public void InvokeNullableEnumParameterDefaultNull()
+ {
+ MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNull", BindingFlags.Static | BindingFlags.NonPublic);
+
+ Assert.Null(Invoke(method, null, new object?[] { default(object) }));
+ Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No }));
+ Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes }));
+
+ if (SupportsMissing)
+ {
+ Assert.Null(Invoke(method, null, new object?[] { Type.Missing }));
+ }
+ }
+
+ [Fact]
+ public void ValueTypeMembers_WithOverrides()
+ {
+ ValueTypeWithOverrides obj = new() { Id = 1 };
+
+ // ToString is overridden.
+ Assert.Equal("Hello", (string)Invoke(GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.ToString)),
+ obj, null));
+
+ // Ensure a normal method works.
+ Assert.Equal(1, (int)Invoke(GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.GetId)),
+ obj, null));
+ }
+
+ [Fact]
+ public void ValueTypeMembers_WithoutOverrides()
+ {
+ ValueTypeWithoutOverrides obj = new() { Id = 1 };
+
+ // ToString is not overridden.
+ Assert.Equal(typeof(ValueTypeWithoutOverrides).ToString(), (string) Invoke(GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.ToString)),
+ obj, null));
+
+ // Ensure a normal method works.
+ Assert.Equal(1, (int)Invoke(GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.GetId)),
+ obj, null));
+ }
+
+ [Fact]
+ public void NullableOfTMembers()
+ {
+ // Ensure calling a method on Nullable<T> works.
+ MethodInfo mi = GetMethod(typeof(int?), nameof(Nullable<int>.GetValueOrDefault));
+ Assert.Equal(42, Invoke(mi, 42, null));
+ }
+
+ [Fact]
+ public void CopyBackWithByRefArgs()
+ {
+ object i = 42;
+ object[] args = new object[] { i };
+ Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByRef)), null, args);
+ Assert.Equal(43, (int)args[0]);
+ Assert.NotSame(i, args[0]); // A copy should be made; a boxed instance should never be directly updated.
+
+ i = 42;
+ args = new object[] { i };
+ Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByNullableRef)), null, args);
+ Assert.Equal(43, (int)args[0]);
+ Assert.NotSame(i, args[0]);
+
+ object o = null;
+ args = new object[] { o };
+ Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNonNullByRef)), null, args);
+ Assert.NotNull(args[0]);
+
+ o = new object();
+ args = new object[] { o };
+ Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNullByRef)), null, args);
+ Assert.Null(args[0]);
+ }
+
+ [Fact]
+ public unsafe void TestFunctionPointerDirect()
+ {
+ // Sanity checks for direct invocation.
+ void* fn = FunctionPointerMethods.GetFunctionPointer();
+ Assert.True(FunctionPointerMethods.GetFunctionPointer()(42));
+ Assert.True(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 42));
+ Assert.True(FunctionPointerMethods.CallFcnPtr_Void(fn, 42));
+ Assert.False(FunctionPointerMethods.GetFunctionPointer()(41));
+ Assert.False(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 41));
+ Assert.False(FunctionPointerMethods.CallFcnPtr_Void(fn, 41));
+ }
+
+ [Fact]
+ public unsafe void TestFunctionPointerAsIntPtrArgType()
+ {
+ void* fn = FunctionPointerMethods.GetFunctionPointer();
+
+ MethodInfo m;
+
+ m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_IntPtr));
+ Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 }));
+ Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 }));
+
+ m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void));
+ Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 }));
+ Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 }));
+ }
+
+ [Fact]
+ public unsafe void TestFunctionPointerAsUIntPtrArgType()
+ {
+ void* fn = FunctionPointerMethods.GetFunctionPointer();
+
+ MethodInfo m;
+
+ m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_UIntPtr));
+ Assert.True((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 42 }));
+ Assert.False((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 41 }));
+
+ m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void));
+ Assert.True((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 42 }));
+ Assert.False((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 41 }));
+ }
+
+ [Fact]
+ public unsafe void TestFunctionPointerAsArgType()
+ {
+ void* fn = FunctionPointerMethods.GetFunctionPointer();
+ MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_FP));
+ Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 }));
+ Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 }));
+ }
+
+ [Fact]
+ public unsafe void TestFunctionPointerAsReturnType()
+ {
+ MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.GetFunctionPointer));
+ object ret = Invoke(m, null, null);
+ Assert.IsType<IntPtr>(ret);
+ Assert.True((IntPtr)ret != 0);
+ }
+ }
+}
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xunit;
-using Xunit.Sdk;
namespace System.Reflection.Tests
{
- public class MethodInfoTests
+ /// <summary>
+ /// These tests use the shared tests from the base class with MethodInfo.Invoke.
+ /// </summary>
+ public sealed class MethodInfoTests : MethodCommonTests
{
+ public override object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters)
+ {
+ return methodInfo.Invoke(obj, parameters);
+ }
+
+ protected override bool SupportsMissing => false;
+
[Fact]
public void CreateDelegate_PublicMethod()
{
[Theory]
[MemberData(nameof(Invoke_TestData))]
- public void Invoke(Type methodDeclaringType, string methodName, object obj, object[] parameters, object result)
+ public void InvokeWithTestData(Type methodDeclaringType, string methodName, object obj, object[] parameters, object result)
{
MethodInfo method = GetMethod(methodDeclaringType, methodName);
Assert.Equal(result, method.Invoke(obj, parameters));
[Fact]
public void Invoke_ParameterSpecification_ArrayOfMissing()
{
- Invoke(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new object[] { Type.Missing }, Type.Missing);
- Invoke(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new Missing[] { Missing.Value }, Missing.Value);
+ InvokeWithTestData(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new object[] { Type.Missing }, Type.Missing);
+ InvokeWithTestData(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new Missing[] { Missing.Value }, Missing.Value);
}
[Fact]
Assert.Equal(expected, methodInfo.ToString());
}
- [Fact]
- public void InvokeNullableRefs()
- {
- object?[] args;
-
- int? iNull = null;
- args = new object[] { iNull };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.Null)).Invoke(null, args));
- Assert.Null(args[0]);
- Assert.False(((int?)args[0]).HasValue);
-
- args = new object[] { iNull };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullBoxed)).Invoke(null, args));
- Assert.Null(args[0]);
-
- args = new object[] { iNull, 10 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValue)).Invoke(null, args));
- Assert.IsType<int>(args[0]);
- Assert.Equal(10, (int)args[0]);
-
- iNull = 42;
- args = new object[] { iNull, 42 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.ValueToNull)).Invoke(null, args));
- Assert.Null(args[0]);
-
- iNull = null;
- args = new object[] { iNull, 10 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValueBoxed)).Invoke(null, args));
- Assert.IsType<int>(args[0]);
- Assert.Equal(10, (int)args[0]);
-
- static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod(
- name, BindingFlags.Public | BindingFlags.Static)!;
- }
-
- [Fact]
- public void InvokeBoxedNullableRefs()
- {
- object?[] args;
-
- object? iNull = null;
- args = new object[] { iNull };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.Null)).Invoke(null, args));
- Assert.Null(args[0]);
-
- args = new object[] { iNull };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullBoxed)).Invoke(null, args));
- Assert.Null(args[0]);
-
- args = new object[] { iNull, 10 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValue)).Invoke(null, args));
- Assert.IsType<int>(args[0]);
- Assert.Equal(10, (int)args[0]);
-
- iNull = 42;
- args = new object[] { iNull, 42 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.ValueToNull)).Invoke(null, args));
- Assert.Null(args[0]);
-
- iNull = null;
- args = new object[] { iNull, 10 };
- Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValueBoxed)).Invoke(null, args));
- Assert.IsType<int>(args[0]);
- Assert.Equal(10, (int)args[0]);
-
- static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod(
- name, BindingFlags.Public | BindingFlags.Static)!;
- }
-
- [Fact]
- public void InvokeEnum()
- {
- // Enums only need to match by primitive type.
- Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)).
- Invoke(null, new object[] { OtherColorsInt.Red }));
-
- // Widening allowed
- Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)).
- Invoke(null, new object[] { ColorsShort.Red }));
-
- // Narrowing not allowed
- Assert.Throws<ArgumentException>(() => GetMethod(nameof(EnumMethods.PassColorsShort)).
- Invoke(null, new object[] { OtherColorsInt.Red }));
-
- static MethodInfo GetMethod(string name) => typeof(EnumMethods).GetMethod(
- name, BindingFlags.Public | BindingFlags.Static)!;
- }
-
- [Fact]
- public static void InvokeNullableEnumParameterDefaultNo()
- {
- MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNo", BindingFlags.Static | BindingFlags.NonPublic);
-
- Assert.Null(method.Invoke(null, new object?[] { default(object) }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { Type.Missing }));
- }
-
- [Fact]
- public static void InvokeNullableEnumParameterDefaultYes()
- {
- MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic);
-
- Assert.Null(method.Invoke(null, new object?[] { default(object) }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { Type.Missing }));
- }
-
- [Fact]
- public static void InvokeNonNullableEnumParameterDefaultYes()
- {
- MethodInfo method = typeof(EnumMethods).GetMethod("NonNullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic);
-
- Assert.Equal(YesNo.No, method.Invoke(null, new object[] { default(object) }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object[] { YesNo.No }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object[] { YesNo.Yes }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object[] { Type.Missing }));
- }
-
- [Fact]
- public static void InvokeNullableEnumParameterDefaultNull()
- {
- MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNull", BindingFlags.Static | BindingFlags.NonPublic);
-
- Assert.Null(method.Invoke(null, new object?[] { default(object) }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes }));
- Assert.Null(method.Invoke(null, new object?[] { Type.Missing }));
- }
-
- [Fact]
- public static void InvokeNullableEnumParameterNoDefault()
- {
- MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumNoDefault", BindingFlags.Static | BindingFlags.NonPublic);
-
- Assert.Null(method.Invoke(null, new object?[] { default(object) }));
- Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No }));
- Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes }));
- Assert.Throws<ArgumentException>(() => method.Invoke(null, new object?[] { Type.Missing }));
- }
-
public static IEnumerable<object[]> MethodNameAndArguments()
{
yield return new object[] { nameof(Sample.DefaultString), "Hello", "Hi" };
}
[Fact]
- public void ValueTypeMembers_WithOverrides()
- {
- ValueTypeWithOverrides obj = new() { Id = 1 };
-
- // ToString is overridden.
- Assert.Equal("Hello", (string)GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.ToString)).
- Invoke(obj, null));
-
- // Ensure a normal method works.
- Assert.Equal(1, (int)GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.GetId)).
- Invoke(obj, null));
- }
-
- [Fact]
- public void ValueTypeMembers_WithoutOverrides()
- {
- ValueTypeWithoutOverrides obj = new() { Id = 1 };
-
- // ToString is not overridden.
- Assert.Equal(typeof(ValueTypeWithoutOverrides).ToString(), (string)GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.ToString)).
- Invoke(obj, null));
-
- // Ensure a normal method works.
- Assert.Equal(1, (int)GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.GetId)).
- Invoke(obj, null));
- }
-
- [Fact]
- public void NullableOfTMembers()
- {
- // Ensure calling a method on Nullable<T> works.
- MethodInfo mi = GetMethod(typeof(int?), nameof(Nullable<int>.GetValueOrDefault));
- Assert.Equal(42, mi.Invoke(42, null));
- }
-
- [Fact]
- public void CopyBackWithByRefArgs()
- {
- object i = 42;
- object[] args = new object[] { i };
- GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByRef)).Invoke(null, args);
- Assert.Equal(43, (int)args[0]);
- Assert.NotSame(i, args[0]); // A copy should be made; a boxed instance should never be directly updated.
-
- i = 42;
- args = new object[] { i };
- GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByNullableRef)).Invoke(null, args);
- Assert.Equal(43, (int)args[0]);
- Assert.NotSame(i, args[0]);
-
- object o = null;
- args = new object[] { o };
- GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNonNullByRef)).Invoke(null, args);
- Assert.NotNull(args[0]);
-
- o = new object();
- args = new object[] { o };
- GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNullByRef)).Invoke(null, args);
- Assert.Null(args[0]);
- }
-
- [Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/69919", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static void CallStackFrame_AggressiveInlining()
Assert.Contains("TestAssembly", asm.ToString());
}
- [Fact]
- private static unsafe void TestFunctionPointerDirect()
- {
- // Sanity checks for direct invocation.
- void* fn = FunctionPointerMethods.GetFunctionPointer();
- Assert.True(FunctionPointerMethods.GetFunctionPointer()(42));
- Assert.True(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 42));
- Assert.True(FunctionPointerMethods.CallFcnPtr_Void(fn, 42));
- Assert.False(FunctionPointerMethods.GetFunctionPointer()(41));
- Assert.False(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 41));
- Assert.False(FunctionPointerMethods.CallFcnPtr_Void(fn, 41));
- }
-
- [Fact]
- private static unsafe void TestFunctionPointerAsIntPtrArgType()
- {
- void* fn = FunctionPointerMethods.GetFunctionPointer();
-
- MethodInfo m;
-
- m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_IntPtr));
- Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 }));
- Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 }));
-
- m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void));
- Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 }));
- Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 }));
- }
-
- [Fact]
- private static unsafe void TestFunctionPointerAsUIntPtrArgType()
- {
- void* fn = FunctionPointerMethods.GetFunctionPointer();
-
- MethodInfo m;
-
- m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_UIntPtr));
- Assert.True((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 42 }));
- Assert.False((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 41 }));
-
- m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void));
- Assert.True((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 42 }));
- Assert.False((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 41 }));
- }
-
- [Fact]
- private static unsafe void TestFunctionPointerAsArgType()
- {
- void* fn = FunctionPointerMethods.GetFunctionPointer();
- MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_FP));
- Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 }));
- Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 }));
- }
-
- [Fact]
- private static unsafe void TestFunctionPointerAsReturnType()
- {
- MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.GetFunctionPointer));
- object ret = m.Invoke(null, null);
- Assert.IsType<IntPtr>(ret);
- Assert.True((IntPtr)ret != 0);
- }
-
//Methods for Reflection Metadata
private void DummyMethod1(string str, int iValue, long lValue)
{
private void DummyMethod2()
{
}
-
- private static MethodInfo GetMethod(Type type, string name)
- {
- return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name));
- }
}
#pragma warning disable 0414
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
-using System.Linq;
using Xunit;
namespace System.Reflection.Tests
{
- public class MethodInvokerTests
+ /// <summary>
+ /// These tests use the shared tests from the base class with MethodInvoker.Invoke.
+ /// </summary>
+ public class MethodInvokerTests : MethodCommonTests
{
+ public override object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters)
+ {
+ return MethodInvoker.Create(methodInfo).Invoke(obj, new Span<object>(parameters));
+ }
+
+ protected override bool SupportsMissing => false;
+
[Fact]
public void NullTypeValidation()
{
Assert.Throws<TargetException>(() => invoker.Invoke(obj: null));
}
- private static MethodInfo GetMethod(Type type, string name)
- {
- return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name));
- }
-
public static IEnumerable<object[]> Invoke_TestData() => MethodInfoTests.Invoke_TestData();
private class TestClass
<RdXmlFile Include="default.rd.xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="$(CommonTestPath)System\Reflection\MockParameterInfo.cs"
- Link="Common\System\Reflection\MockParameterInfo.cs" />
- <Compile Include="$(CommonTestPath)System\MockType.cs"
- Link="Common\System\MockType.cs" />
- <Compile Include="$(CommonTestPath)System\IO\TempFile.cs"
- Link="Common\System\IO\TempFile.cs" />
+ <Compile Include="$(CommonTestPath)System\Reflection\MockParameterInfo.cs" Link="Common\System\Reflection\MockParameterInfo.cs" />
+ <Compile Include="$(CommonTestPath)System\MockType.cs" Link="Common\System\MockType.cs" />
+ <Compile Include="$(CommonTestPath)System\IO\TempFile.cs" Link="Common\System\IO\TempFile.cs" />
<Compile Include="AssemblyNameTests.cs" />
<Compile Include="AssemblyTests.cs" />
+ <Compile Include="ConstructorCommonTests.cs" />
<Compile Include="ConstructorInfoTests.cs" />
<Compile Include="ConstructorInvokerTests.cs" />
<Compile Include="CustomAttributeTests.cs" />
<Compile Include="GetTypeTests.cs" />
<Compile Include="ManifestResourceInfoTests.cs" />
<Compile Include="MemberInfoTests.cs" />
+ <Compile Include="MethodCommonTests.cs" />
<Compile Include="MethodInfoTests.cs" />
<Compile Include="MethodInvokerTests.cs" />
<Compile Include="ModuleTests.cs" />
<Compile Include="ExceptionTests.cs" />
<Compile Include="PointerTests.cs" />
<Compile Include="TypeTests.Constraints.cs" />
- <Compile Include="TestAssembly\EquivalentValueType.cs"
- Link="EquivalentValueType.cs" />
+ <Compile Include="TestAssembly\EquivalentValueType.cs" Link="EquivalentValueType.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\EmbeddedImage.png">