Let's say I have a type
, which I know to be derived from a Delegate
type. I would like to create an object of this type wrapping an anonymous delegate that accepts arbitrary params and returns an object of correct return type:
var retType = type.GetMethod("Invoke").ReturnType;
var obj = Delegate.CreateDelegate(type, delegate(object[] args) {
...
if (retType != typeof(void))
... somehow create object of type retType and return it ...
});
Obviously this won't compile, because CreateDelegate
expects a MethodInfo
as the second argument. How can I do this correctly?
Update: A little more info on what I am trying to achieve. There are two applications running - client in a browser and a server in C#. Browser is able to call remote functions on the server side by serializing arguments to JSON and sending the call over the network (like in RPC). This works already, but I would like to add support for callbacks. For example:
JavaScript (client):
function onNewObject(uuid) { console.log(uuid); }
server.notifyAboutNewObjects(onNewObject);
C# (server):
void notifyAboutNewObjects(Action<string> callback) {
...
callback("new-object-uuid");
...
}
The middleware code will receive a call from the browser and will need to generate fake callback
delegate that will actually send the call to callback
back to the browser and block the thread until it completes. The code for sending/receiving is there already, I am just stuck on how to generate a generic delegate that will simply put all arguments into an array and pass them to the sending code.
Update: If someone can write code that will generate such a delegate at runtime (e.g. using DynamicMethod) , I'll consider that a valid answer. I just don't have enough time to learn how to do this and hope that someone experienced will be able to write this code quickly enough. Essentially the code should just take arbitrary delegate params (list and types are available at runtime), put them into an array and call generic method. The generic method will always return an object
, which should be cast into respective return type or ignored if the function returns void
.
Uppdate: I've created a small test program that demonstrates what I need:
using System;
using System.Reflection;
namespace TestDynamicDelegates
{
class MainClass
{
// Test function, for which we need to create default parameters.
private static string Foobar(float x, Action<int> a1, Func<string, string> a2) {
a1(42);
return a2("test");
}
// Delegate to represent generic function.
private delegate object AnyFunc(params object[] args);
// Construct a set of default parameters to be passed into a function.
private static object[] ConstructParams(ParameterInfo[] paramInfos)
{
object[] methodParams = new object[paramInfos.Length];
for (var i = 0; i < paramInfos.Length; i++) {
ParameterInfo paramInfo = paramInfos[i];
if (typeof(Delegate).IsAssignableFrom(paramInfo.ParameterType)) {
// For delegate types we create a delegate that maps onto a generic function.
Type retType = paramInfo.ParameterType.GetMethod("Invoke").ReturnType;
// Generic function that will simply print arguments and create default return value (or return null
// if return type is void).
AnyFunc tmpObj = delegate(object[] args) {
Console.WriteLine("Invoked dynamic delegate with following parameters:");
for (var j = 0; j < args.Length; j++)
Console.WriteLine(" {0}: {1}", j, args[j]);
if (retType != typeof(void))
return Activator.CreateInstance(retType);
return null;
};
// Convert generic function to the required delegate type.
methodParams[i] = /* somehow cast tmpObj into paramInfo.ParameterType */
} else {
// For all other argument type we create a default value.
methodParams[i] = Activator.CreateInstance(paramInfo.ParameterType);
}
}
return methodParams;
}
public static void Main(string[] args)
{
Delegate d = (Func<float, Action<int>,Func<string,string>,string>)Foobar;
ParameterInfo[] paramInfo = d.Method.GetParameters();
object[] methodParams = ConstructParams(paramInfo);
Console.WriteLine("{0} returned: {1}", d.Method.Name, d.DynamicInvoke(methodParams));
}
}
}
I wrote a opensource PCL library, called Dynamitey (in nuget), that does all sorts of dynamic things using the C# DLR. .
It specifically has a static method called
Dynamic.CoerceToDelegate(object invokeableObject, Type delegateType)
That basically wraps the dynamic invocation of aDynamicObject
or a more general delegate, with the specific Type of delegate using CompiledExpressions (source).using System.Dynamic you can create an invokable object:
Then in your sample:
How about a solution without delegates? (warning: rampant pseudocode)
messages will be serialized anyway, so why bother? Polymorphism will take care of the rest. The only requirement is to have a set of messages which correspond to each event type.
Returning the value may be implemented by writing to some field in the
AbstractServerToClientMessage
.Or, you can actually have a delegate with a fixed signature accepting a similar
AbstractServerToClientMessage
. Again, polymorphism (+ a class factory for deserialization) will allow to cast it to correct type of message.You could either check out the source code for SignalR or simply just use it.
Register a function in browser that the server can call
and on the server
See here for more examples.