Skip to content

Commit

Permalink
Improvements in Reflection
Browse files Browse the repository at this point in the history
- Add MethodBase.GetParameters().
- Add Type.GetConstructors().
- Add ParameterInfo class.
- Add Unit Tests to cover the new classes.
- Bump AssemblyNativeVersion to 100.5.0.16.
  • Loading branch information
josesimoes committed Jan 28, 2022
1 parent a22fc17 commit 93df8ab
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 1 deletion.
174 changes: 174 additions & 0 deletions Tests/NFUnitTestClasses/UnitTestConstructorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(2, constructors.Length, $"Expecting 2 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_08()
{
// constructor for derived class
var classToTest = typeof(ConstructorsTestClass44);

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 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
{
Expand Down Expand Up @@ -1567,5 +1724,22 @@ 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;
}
}

}
}
1 change: 1 addition & 0 deletions nanoFramework.CoreLibrary/CoreLibrary.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
<Compile Include="System\Reflection\AssemblyReflectionAttributes.cs" />
<Compile Include="System\Reflection\Binder.cs" />
<Compile Include="System\Reflection\BindingFlags.cs" />
<Compile Include="System\Reflection\ParameterInfo.cs" />
<Compile Include="System\Reflection\ConstructorInfo.cs" />
<Compile Include="System\Reflection\CustomAttributesHelpers.cs" />
<Compile Include="System\Reflection\DefaultMemberAttribute.cs" />
Expand Down
2 changes: 1 addition & 1 deletion nanoFramework.CoreLibrary/System/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
12 changes: 12 additions & 0 deletions nanoFramework.CoreLibrary/System/Reflection/MethodBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ namespace System.Reflection
[Serializable]
public abstract class MethodBase : MemberInfo
{
// required to store native
private int _token;

/// <summary>
/// Gets a value indicating whether this is a public method.
/// </summary>
Expand Down Expand Up @@ -78,6 +81,12 @@ public extern bool IsAbstract
get;
}

/// <summary>
/// When overridden in a derived class, gets the parameters of the specified method or constructor.
/// </summary>
/// <returns>An array of type <see cref="ParameterInfo"/> containing information that matches the signature of the method (or constructor) reflected by this <see cref="MethodBase"/> instance.</returns>
public abstract ParameterInfo[] GetParameters();

/// <summary>
/// Invokes the method or constructor represented by the current instance, using the specified parameters.
/// </summary>
Expand Down Expand Up @@ -114,6 +123,9 @@ public override extern Type DeclaringType
[MethodImpl(MethodImplOptions.InternalCall)]
get;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern ParameterInfo[] GetParametersNative();
}
}

Expand Down
33 changes: 33 additions & 0 deletions nanoFramework.CoreLibrary/System/Reflection/ParameterInfo.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Discovers the attributes of a parameter and provides access to parameter metadata.
/// </summary>
/// <remarks>Available only in mscorlib build with support for System.Reflection.</remarks>
[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

/// <summary>
/// Gets the <see cref="Type"/> of this parameter.
/// </summary>
/// <value>The <see cref="Type"/> object that represents the <see cref="Type"/> of this parameter.</value>
public virtual Type ParameterType => _parameterType;
}
}

#endif // NANOCLR_REFLECTION
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
9 changes: 9 additions & 0 deletions nanoFramework.CoreLibrary/System/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ public abstract Type BaseType
[MethodImpl(MethodImplOptions.InternalCall)]
public extern ConstructorInfo GetConstructor(Type[] types);

/// <summary>
/// Returns all the public constructors defined for the current <see cref="Type"/>.
/// </summary>
/// <returns>
/// An array of <see cref="ConstructorInfo"/> objects representing all the public instance constructors defined for the current <see cref="Type"/>, but not including the type initializer (static constructor). If no public instance constructors are defined for the current <see cref="Type"/>, or if the current <see cref="Type"/> represents a type parameter in the definition of a generic type or generic method, an empty array of type <see cref="ConstructorInfo"/> is returned.
/// </returns>
[MethodImpl(MethodImplOptions.InternalCall)]
public extern ConstructorInfo[] GetConstructors();

/// <summary>
/// Searches for the specified public method whose parameters match the specified argument types.
/// </summary>
Expand Down

0 comments on commit 93df8ab

Please sign in to comment.