C
C#10mo ago
jborean

Invoke method with [Optional] with default value through Reflection

Is it possible to through reflection to invoke a method with an [Optional] attribute. For example Type.Missing works for an argument with a default value but not for an [Optional] argument.
using System;
using System.Reflection;
using System.Runtime.InteropServices;

public class Program
{
public static void Main(string[] args)
{
object? test1 = typeof(Program).GetMethod("MethodWithDefault").Invoke(null, new[] { Type.Missing });
object? test2 = typeof(Program).GetMethod("MethodWithOptional").Invoke(null, new[] { Type.Missing });
Console.WriteLine(test1);
Console.WriteLine(test2);
}

public static int MethodWithDefault(int value = 1) => value;
public static int MethodWithOptional([Optional]int value) => value;
}
using System;
using System.Reflection;
using System.Runtime.InteropServices;

public class Program
{
public static void Main(string[] args)
{
object? test1 = typeof(Program).GetMethod("MethodWithDefault").Invoke(null, new[] { Type.Missing });
object? test2 = typeof(Program).GetMethod("MethodWithOptional").Invoke(null, new[] { Type.Missing });
Console.WriteLine(test1);
Console.WriteLine(test2);
}

public static int MethodWithDefault(int value = 1) => value;
public static int MethodWithOptional([Optional]int value) => value;
}
1 Reply
jborean
jboreanOP10mo ago
I'm assuming I'll have to get the ParameterInfo for the argument, check if IsOptional and use DefaultValue to get the default value to pass in rather than Type.Missing Hmm no that won't work as the DefaultValue is Type.Missing when no explicit default value is set
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public class MyClass
{
public static int TestMethod1(int value = 1) => value;
public static int TestMethod2([Optional] int value) => value;
public static int TestMethod3([Optional, DefaultParameterValue(1)] int value) => value;
}
'@

[MyClass].GetMethod('TestMethod1').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : True
DefaultValue : 1
RawDefaultValue : 1
MetadataToken : 134217729
Attributes : Optional, HasDefault
Member : Int32 TestMethod1(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}

[MyClass].GetMethod('TestMethod2').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : False
DefaultValue : System.Reflection.Missing
RawDefaultValue : System.Reflection.Missing
MetadataToken : 134217730
Attributes : Optional
Member : Int32 TestMethod2(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}

[MyClass].GetMethod('TestMethod3').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : True
DefaultValue : 1
RawDefaultValue : 1
MetadataToken : 134217731
Attributes : Optional, HasDefault
Member : Int32 TestMethod3(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public class MyClass
{
public static int TestMethod1(int value = 1) => value;
public static int TestMethod2([Optional] int value) => value;
public static int TestMethod3([Optional, DefaultParameterValue(1)] int value) => value;
}
'@

[MyClass].GetMethod('TestMethod1').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : True
DefaultValue : 1
RawDefaultValue : 1
MetadataToken : 134217729
Attributes : Optional, HasDefault
Member : Int32 TestMethod1(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}

[MyClass].GetMethod('TestMethod2').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : False
DefaultValue : System.Reflection.Missing
RawDefaultValue : System.Reflection.Missing
MetadataToken : 134217730
Attributes : Optional
Member : Int32 TestMethod2(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}

[MyClass].GetMethod('TestMethod3').GetParameters()

ParameterType : System.Int32
Name : value
HasDefaultValue : True
DefaultValue : 1
RawDefaultValue : 1
MetadataToken : 134217731
Attributes : Optional, HasDefault
Member : Int32 TestMethod3(Int32)
Position : 0
IsIn : False
IsLcid : False
IsOptional : True
IsOut : False
IsRetval : False
CustomAttributes : {[System.Runtime.InteropServices.OptionalAttribute()]}
I realised I never shared the error when trying to use Invoke(null, new[] { Type.Missing }); for TestMethod2, it is
Object of type 'System.Reflection.Missing' cannot be converted to type 'System.Int32'.
Object of type 'System.Reflection.Missing' cannot be converted to type 'System.Int32'.
It does work for TestMethod1 and TestMethod3 though Opened https://github.com/dotnet/runtime/issues/100322
Want results from more Discord servers?
Add your server