From fe5185901c7fe48f7063e853a037acf9b599aa77 Mon Sep 17 00:00:00 2001 From: josesimoes Date: Fri, 28 Jan 2022 09:27:54 +0000 Subject: [PATCH] Improvements in Reflection - Add MethodBase.GetParameters(). - Add Type.GetConstructors(). - Add ParameterInfo class. - Add Unit Tests to cover the new classes. - Bump AssemblyNativeVersion to 100.5.0.16. --- .../UnitTestConstructorTest.cs | 173 ++++++++++++++++++ nanoFramework.CoreLibrary/CoreLibrary.nfproj | 1 + .../System/AssemblyInfo.cs | 2 +- .../System/Reflection/MethodBase.cs | 12 ++ .../System/Reflection/ParameterInfo.cs | 33 ++++ .../Reflection/RuntimeConstructorInfo.cs | 5 + .../System/Reflection/RuntimeMethodInfo.cs | 5 + nanoFramework.CoreLibrary/System/Type.cs | 9 + 8 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 nanoFramework.CoreLibrary/System/Reflection/ParameterInfo.cs diff --git a/Tests/NFUnitTestClasses/UnitTestConstructorTest.cs b/Tests/NFUnitTestClasses/UnitTestConstructorTest.cs index f6581dd8..71e210d1 100644 --- a/Tests/NFUnitTestClasses/UnitTestConstructorTest.cs +++ b/Tests/NFUnitTestClasses/UnitTestConstructorTest.cs @@ -362,6 +362,163 @@ public void Constructors64_Test() Assert.True(ConstructorsTestClass64.testMethod()); } + [TestMethod] + public void ConstructorName_01() + { + var classToTest = typeof(ClassWith3Constructors); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(3, constructors.Length, $"Expecting 3 constructors, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_02() + { + var classToTest = typeof(ConstructorsTestClass2); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_03() + { + // constructor without modifier + var classToTest = typeof(ConstructorsTestClass3); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_04() + { + // internal constructor + var classToTest = typeof(ConstructorsTestClass5); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_05() + { + // private constructor + var classToTest = typeof(ConstructorsTestClass6); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_06() + { + // static constructor + var classToTest = typeof(ConstructorsTestClass35); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_07() + { + // constructor for base class + var classToTest = typeof(ConstructorsTestClass44_Base); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorName_08() + { + // constructor for derived class + var classToTest = typeof(ConstructorsTestClass44); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + Assert.Equal(1, constructors.Length, $"Expecting 1 constructor, got {constructors.Length}."); + + foreach (ConstructorInfo constructorInfo in constructors) + { + Assert.Equal(constructorInfo.Name, ".ctor", $"Expecting '.ctor' as constructor name, but got: {constructorInfo.Name}"); + } + } + + [TestMethod] + public void ConstructorParametersInfo_01() + { + var classToTest = typeof(ClassWith3Constructors); + + ConstructorInfo[] constructors = classToTest.GetConstructors(); + + // get ParameterInfo for 1st constructor + ParameterInfo[] constructorParameters = constructors[0].GetParameters(); + + OutputHelper.WriteLine("Checking parameters for 1st constructor of ClassWith3Constructors"); + Assert.Equal(0, constructorParameters.Length, $"Expecting no parameters, got {constructorParameters.Length}."); + + // get ParameterInfo for 2nd constructor + constructorParameters = constructors[1].GetParameters(); + + Assert.Equal(1, constructorParameters.Length, $"Expecting 1 parameter, got {constructorParameters.Length}."); + + OutputHelper.WriteLine("Checking parameters for 2nd constructor of ClassWith3Constructors"); + Assert.Equal(constructorParameters[0].ParameterType.ToString(), $"{typeof(int)}", $"Expecting parameter of type {typeof(int)}, got {constructorParameters[0].ParameterType}."); + + // get ParameterInfo for 3rd constructor + constructorParameters = constructors[2].GetParameters(); + + Assert.Equal(1, constructorParameters.Length, $"Expecting 2 parameters, got {constructorParameters.Length}."); + + OutputHelper.WriteLine("Checking parameters for 3rd constructor of ClassWith3Constructors"); + Assert.Equal(constructorParameters[0].ParameterType.ToString(), $"{typeof(int)}", $"Expecting parameter of type {typeof(int)}, got {constructorParameters[0].ParameterType}."); + Assert.Equal(constructorParameters[1].ParameterType.ToString(), $"{typeof(string)}", $"Expecting parameter of type {typeof(string)}, got {constructorParameters[0].ParameterType}."); + } + //Constructors Test Classes class ConstructorsTestClass1 { @@ -1567,5 +1724,21 @@ public static bool testMethod() return true; } } + + public class ClassWith3Constructors + { + public int intValue = 0; + public string stringValue = ""; + + public ClassWith3Constructors() { } + + public ClassWith3Constructors(int intValue) { this.intValue = intValue; } + + public ClassWith3Constructors(int intValue, string stringValue) + { + this.intValue = intValue; + this.stringValue = stringValue; + } + } } } diff --git a/nanoFramework.CoreLibrary/CoreLibrary.nfproj b/nanoFramework.CoreLibrary/CoreLibrary.nfproj index 5794657d..dc9240c5 100644 --- a/nanoFramework.CoreLibrary/CoreLibrary.nfproj +++ b/nanoFramework.CoreLibrary/CoreLibrary.nfproj @@ -140,6 +140,7 @@ + diff --git a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs index def3480a..66c15097 100644 --- a/nanoFramework.CoreLibrary/System/AssemblyInfo.cs +++ b/nanoFramework.CoreLibrary/System/AssemblyInfo.cs @@ -13,4 +13,4 @@ [assembly: AssemblyProduct(".NET nanoFramework mscorlib")] [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] -[assembly: AssemblyNativeVersion("100.5.0.15")] +[assembly: AssemblyNativeVersion("100.5.0.16")] diff --git a/nanoFramework.CoreLibrary/System/Reflection/MethodBase.cs b/nanoFramework.CoreLibrary/System/Reflection/MethodBase.cs index 737dbca2..82d8ac31 100644 --- a/nanoFramework.CoreLibrary/System/Reflection/MethodBase.cs +++ b/nanoFramework.CoreLibrary/System/Reflection/MethodBase.cs @@ -18,6 +18,9 @@ namespace System.Reflection [Serializable] public abstract class MethodBase : MemberInfo { + // required to store native + private int _token; + /// /// Gets a value indicating whether this is a public method. /// @@ -78,6 +81,12 @@ public extern bool IsAbstract get; } + /// + /// When overridden in a derived class, gets the parameters of the specified method or constructor. + /// + /// An array of type containing information that matches the signature of the method (or constructor) reflected by this instance. + public abstract ParameterInfo[] GetParameters(); + /// /// Invokes the method or constructor represented by the current instance, using the specified parameters. /// @@ -114,6 +123,9 @@ public override extern Type DeclaringType [MethodImpl(MethodImplOptions.InternalCall)] get; } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern ParameterInfo[] GetParametersNative(); } } diff --git a/nanoFramework.CoreLibrary/System/Reflection/ParameterInfo.cs b/nanoFramework.CoreLibrary/System/Reflection/ParameterInfo.cs new file mode 100644 index 00000000..984d59a7 --- /dev/null +++ b/nanoFramework.CoreLibrary/System/Reflection/ParameterInfo.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#if NANOCLR_REFLECTION + +namespace System.Reflection +{ + using Runtime.CompilerServices; + using System; + + /// + /// Discovers the attributes of a parameter and provides access to parameter metadata. + /// + /// Available only in mscorlib build with support for System.Reflection. + [Serializable] + public abstract class ParameterInfo + { +#pragma warning disable S3459 // required to fill in in native code + private readonly Type _parameterType; +#pragma warning restore S3459 // Unassigned members should be removed + + /// + /// Gets the of this parameter. + /// + /// The object that represents the of this parameter. + public virtual Type ParameterType => _parameterType; + } +} + +#endif // NANOCLR_REFLECTION diff --git a/nanoFramework.CoreLibrary/System/Reflection/RuntimeConstructorInfo.cs b/nanoFramework.CoreLibrary/System/Reflection/RuntimeConstructorInfo.cs index df418ac1..b16d646f 100644 --- a/nanoFramework.CoreLibrary/System/Reflection/RuntimeConstructorInfo.cs +++ b/nanoFramework.CoreLibrary/System/Reflection/RuntimeConstructorInfo.cs @@ -9,10 +9,15 @@ namespace System.Reflection { using System; + using System.Runtime.CompilerServices; [Serializable] internal sealed class RuntimeConstructorInfo : ConstructorInfo { + public override ParameterInfo[] GetParameters() + { + return GetParametersNative(); + } } } diff --git a/nanoFramework.CoreLibrary/System/Reflection/RuntimeMethodInfo.cs b/nanoFramework.CoreLibrary/System/Reflection/RuntimeMethodInfo.cs index 8fea5e20..5dee51eb 100644 --- a/nanoFramework.CoreLibrary/System/Reflection/RuntimeMethodInfo.cs +++ b/nanoFramework.CoreLibrary/System/Reflection/RuntimeMethodInfo.cs @@ -25,6 +25,11 @@ public override object[] GetCustomAttributes(bool inherit) return CustomAttributesHelpers.GetCustomAttributesInternal(GetCustomAttributesNative(inherit)); } + public override ParameterInfo[] GetParameters() + { + return GetParametersNative(); + } + [MethodImpl(MethodImplOptions.InternalCall)] private extern object[] GetCustomAttributesNative(bool inherit); } diff --git a/nanoFramework.CoreLibrary/System/Type.cs b/nanoFramework.CoreLibrary/System/Type.cs index 7f8e1232..a162798f 100644 --- a/nanoFramework.CoreLibrary/System/Type.cs +++ b/nanoFramework.CoreLibrary/System/Type.cs @@ -148,6 +148,15 @@ public abstract Type BaseType [MethodImpl(MethodImplOptions.InternalCall)] public extern ConstructorInfo GetConstructor(Type[] types); + /// + /// Returns all the public constructors defined for the current . + /// + /// + /// An array of objects representing all the public instance constructors defined for the current , but not including the type initializer (static constructor). If no public instance constructors are defined for the current , or if the current represents a type parameter in the definition of a generic type or generic method, an empty array of type is returned. + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public extern ConstructorInfo[] GetConstructors(); + /// /// Searches for the specified public method whose parameters match the specified argument types. ///