Rettoph
Rettoph
CC#
Created by Rettoph on 9/24/2024 in #help
Generically creating a delegate from a MethodInfo with parameter upcasting
I am trying to create a delegate of type TDelegate that allows me to invoke a MethodInfo instance with some upcasted parameters. A simple example of what i want is as follows:
using System.Reflection;

MethodInfo someFunctionMethodInfo = typeof(MyTestClass).GetMethod(nameof(MyTestClass.SomeFunction), BindingFlags.Static | BindingFlags.Public)!;

// Note, SomeFunction is an Action<object> and i want an Action<int>
// System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'
var customDelegateUpcasting = DelegateHelper.CreateDelegateWithCasting<Action<int>>(someFunctionMethodInfo);
customDelegateUpcasting(10);

// Desired output:
// SomeFunction invoked with parameter: 10, Type: System.Int32

Console.ReadLine();

class DelegateHelper
{
public static TDelegate CreateDelegateWithCasting<TDelegate>(MethodInfo method)
where TDelegate : Delegate
{
// Currently throws:
// System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'
return method.CreateDelegate<TDelegate>();
}
}

class MyTestClass
{
public static void SomeFunction(object param)
{
Console.WriteLine($"{nameof(SomeFunction)} invoked with parameter: {param}, Type: {param.GetType()}");
}
}
using System.Reflection;

MethodInfo someFunctionMethodInfo = typeof(MyTestClass).GetMethod(nameof(MyTestClass.SomeFunction), BindingFlags.Static | BindingFlags.Public)!;

// Note, SomeFunction is an Action<object> and i want an Action<int>
// System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'
var customDelegateUpcasting = DelegateHelper.CreateDelegateWithCasting<Action<int>>(someFunctionMethodInfo);
customDelegateUpcasting(10);

// Desired output:
// SomeFunction invoked with parameter: 10, Type: System.Int32

Console.ReadLine();

class DelegateHelper
{
public static TDelegate CreateDelegateWithCasting<TDelegate>(MethodInfo method)
where TDelegate : Delegate
{
// Currently throws:
// System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'
return method.CreateDelegate<TDelegate>();
}
}

class MyTestClass
{
public static void SomeFunction(object param)
{
Console.WriteLine($"{nameof(SomeFunction)} invoked with parameter: {param}, Type: {param.GetType()}");
}
}
The tldr, i want to take method void SomeFunction(object param) and create a delegate Action<int>... generically In this example im just calling MethodInfo::CreateDelegate<TDelegate>() - which fails. This is fine, i expect and understand why this happens. I'm just looking for ideas to achieve what im looking for. traditionally, i might just wrap the MethodInfo invocation within a lambda and call it a day... but since TDelegate is a generic type i dont actually know the number of parameters until the CreateDelegateWithCasting helper method is called - which is where my problem lies.
2 replies
CC#
Created by Rettoph on 11/30/2023 in #help
Contravariant Help
Given the following code:
c#
MySubscriber subscriber = new MySubscriber();

class MessageA { }
class MessageB : MessageA { }
class MessageC : MessageB { }

// note the in keyword here
interface ISubscriber<in T>
{
void Process(T message);
}

class MySubscriber : ISubscriber<MessageA>, ISubscriber<MessageB>
{
void ISubscriber<MessageA>.Process(MessageA message)
{
Console.WriteLine("Processing MessageA");
}

void ISubscriber<MessageB>.Process(MessageB message)
{
Console.WriteLine("Processing MessageB");
}
}
c#
MySubscriber subscriber = new MySubscriber();

class MessageA { }
class MessageB : MessageA { }
class MessageC : MessageB { }

// note the in keyword here
interface ISubscriber<in T>
{
void Process(T message);
}

class MySubscriber : ISubscriber<MessageA>, ISubscriber<MessageB>
{
void ISubscriber<MessageA>.Process(MessageA message)
{
Console.WriteLine("Processing MessageA");
}

void ISubscriber<MessageB>.Process(MessageB message)
{
Console.WriteLine("Processing MessageB");
}
}
How might I take an instance of MySubscriber and create a ISubscriber<MessageC>[] with 2 values. The first being the ISubscriber<MessageA> implementation, and the second being the ISubscriber<MessageB> implementation?
8 replies