CreateDelegate fails due to delegate signature mismatch - c#

I am consuming a web service which has a number of methods (50) which create different objects.
example:
CreateObject1(Object1 obj, int arg2)
CreateObject2(Object2 obj, int arg2)
...
CreateObjectX(ObjectX obj, int arg2)
All Objects (Object1, Object2, ObjectX...) inherit from ObjectBase.
So I am trying to do this...
delegate void DlgtCreateObject(ObjectBase obj, int arg2);
public void CreateObject(ObjectBase obj, int arg2)
{
DlgtCreateObject dlgt;
string objType;
string operation;
objType = obj.GetType().ToString();
operation = "Create" + objType.Substring(objType.LastIndexOf(".") + 1);
using (MyWebService service = new MyWebService())
{
dlgt = (DlgtCreateObject)Delegate.CreateDelegate(typeof(DlgtCreateObject),
service,
operation,
false,
true);
dlgt(obj, arg2);
}
}
Unfortunately this gives me a Failed to Bind exception.
I believe this is because my delegate signature uses the ObjectBase as its first argument where the functions use the specific classes.
Is there a way around this?

If you're only trying to call the methods within here, I suggest you use Type.GetMethod and MethodBase.Invoke instead of going via delegates. Then you won't run into this problem.

Right after posting I figured generics might be the answer, and indeed the following seems to do the trick...
delegate void DlgtCreateObject<T>(T obj, int arg2) where T : ObjectBase;
public void CreateObject<T>(T obj, int arg2) where T : ObjectBase;
{
DlgtCreateObject dlgt;
string objType;
string operation;
objType = obj.GetType().ToString();
operation = "Create" + objType.Substring(objType.LastIndexOf(".") + 1);
using (MyWebService service = new MyWebService())
{
dlgt = (DlgtCreateObject<T>)Delegate.CreateDelegate(typeof(DlgtCreateObject<T>),
service,
operation,
false,
true);
dlgt(obj, arg2);
}
}

Related

Is there any abstraction in .NET that encapsulates MethodInfo + instance?

I'm playing with Reflection and I would like to encapsulate a call to an instance method.
I always end up doing something like this:
methodInfo.Invoke(instance, parameters)
I wonder if there's any way to encapsulate it to something like call.Invoke(parameters), where the instance is implicit.
You can create a delegate that binds the instance.
You can do this either with the static Delegate.CreateInstance method or with the MethodInfo.CrateInstance method. The former relies on you knowing that the instance is actually a hidden first parameter to the method, so the latter may be a little more clear.
class Thing
{
int _Number;
public Thing(int number) { _Number = number; }
public int GetNumber() { return _Number; }
}
public static void Main()
{
Thing thingOne = new Thing(1);
Thing thingTwo = new Thing(2);
MethodInfo getter = typeof(Thing).GetMethod("GetNumber");
Func<int> getOne = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), thingOne, getter);
Func<int> getTwo = (Func<int>)getter.CreateDelegate(typeof(Func<int>), thingTwo);
Console.WriteLine(getOne());
Console.WriteLine(getTwo());
}
Why not simply this:
public class MethodInvoker
{
private MethodInfo _method;
private object _target;
public MethodInvoker(MethodInfo method, object target)
{
_method = method;
_target = target;
}
public object Invoke(params object[] parameters) => _method.Invoke(_target, parameters);
}
...
string s = "Hello";
var invoker = new MethodInvoker(s.GetType().GetMethod("Substring",new Type[] { typeof(int), typeof(int) }), s);
Console.WriteLine(invoker.Invoke(1,3));
You might use generics for type safety on the target or return type.

c# calling endinvoke in callback, using generics

Inisde the callback after BeginInvoke, AsyncResult.AsyncDelegate needs to be cast to proper type, only then EndInvoke is accessible.
But I am using generics, so do I need to define N callbacks for N generalized methods?
This is the class:
public class Async
{
public delegate object Func(); //void with no parameter
public delegate TResult Func<T, TResult>(T arg); //one parameter with result
public static void Execute(IAsyncSubscriber subscriber, Func action)
{
action.BeginInvoke(Callback, subscriber);
}
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback, subscriber);
}
private static void Callback(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
IAsyncSubscriber subscriber = (IAsyncSubscriber)result.AsyncState;
Func action = (Func) result.AsyncDelegate;
object returnValue = action.EndInvoke(result); //To call endinvoke
subscriber.Callback(returnValue);
}
}
There are a few ways in which you can avoid defining N callbacks:
You can pass the corresponding EndInvoke method as state in the BeginInvoke call. e.g.
private delegate T EndInvokeDelegate<T>(IAsyncResult ar);
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback<T1>, new object[]{subscriber, new new EndInvokeDelegate<T1>(action.EndInvoke)});
}
public static void Execute<T, T1, T2>(IAsyncSubscriber subscriber, T param1, T1 param2, Func<T, T1, T2> action)
{
action.BeginInvoke(param1, param2, Callback<T2>, new object[]{subscriber, new new EndInvokeDelegate<T2>(action.EndInvoke)});
}
private static void Callback<TR>(IAsyncResult ar)
{
object[] stateArr = (object[])ar.AsyncState;
IAsyncSubscriber subscriber = (IAsyncSubscriber)stateArr[0];
EndInvokeDelegate<TR> action = (EndInvokeDelegate<TR>)stateArray[1];
TR returnValue = action(ar);
subscriber.Callback(returnValue);
}
You can also make Callback non-generic by treating stateArray[1] as MultiCastDelegate and using DynamicInvoke on it but that would be slow.
For .Net 2.0 and 3.0, you can use reflection e.g.
Type actionType= result.AsyncDelegate.GetType();
var minfo = actionType.GetMethod("EndInvoke");
object returnValue = minfo.Invoke(res.AsyncDelegate, new object[] { ar });
For .Net 4.0, you can use dynamic. e.g.
dynamic action = result.AsyncDelegate;
object returnValue = action.EndInvoke(result);
If I understand correctly, your assumption is correct. You will need to define N callbacks.
On the bright side, you will only be doing this once, so no biggy, just a little repetitive work :)

Is it legal to assign by ref to a field using IL?

There is as far as I know no way to interact with reference types in Expression trees. (e.g. nothing emits a stind.* or a ldind.* opcode).
I'm working on a bit of a rewriter to get around this annoyance. Since I'm building a new type that has the method body replaced with delegate invocations (to get around the fact that CompileToMethod can only do static methods that can't interact with new members). For by-ref and out parameters, I thought I'd replace their usages with StrongBox<T>.
So if I came across a method that has a signature that looks like this::
public class SomeClass
{
public virtual bool SomeMethod(string arg1,ref int arg2)
{
}
}
The override, the callbase method, and the delegate field I generate will look like this::
public class SomeClass<1> : SomeClass
{
private static bool SomeMethod<0>(
SomeClass target,string arg1,StrongBox<int> arg2)
{
return call target.SomeMethod(arg1,ref arg2.Value)
}
private Func<SomeClass,string,StrongBox<int>,bool> <0>SomeMethod;
public override bool SomeMethod(string arg1,ref int arg2)
{
StrongBox<int> box = new StrongBox<int>();
box.Value = arg2;
bool retVal = <0>SomeMethod.Invoke(this,arg1,box);
arg2 = box.Value;
return retVal;
}
}
However, this is quite a lot of code to perform this conversion, for each parameter it introduces a lot of complexity. It would be much easier when I perform the setting of box.Value = arg2, if I could do something like &box.Value = &arg2 that is assign it's address to the address of arg2 as it stands. That way when the delegate performs a mutation on the value field the changes are forwarded. Doing this means I don't need to have to have a variable to hold the return value, and I don't need to perform a reference value update.
Alternatively, if there is a way to perform assign-by-ref semantics with Expression trees, I'm all ears of course.
Not sure if I really understand but maybe this is a solution:
class Program
{
public class SomeClass
{
private readonly int _n;
public SomeClass(int n) { _n = n; }
public virtual bool SomeMethod(string arg1, ref int arg2) {
if (String.IsNullOrWhiteSpace(arg1)) return false;
arg2 += arg1.Length + _n;
return true;
}
}
private delegate bool SomeDelegate(SomeClass that, string arg1, ref int arg2);
static void Main(string[] args) {
var instance = Expression.Parameter(typeof (SomeClass), "that");
var arg1Param = Expression.Parameter(typeof(string), "arg1");
var arg2Param = Expression.Parameter(typeof (int).MakeByRefType(), "arg2");
var someMethodInfo = typeof (SomeClass).GetMethod("SomeMethod");
var lambda = Expression.Lambda<SomeDelegate>(Expression.Call(instance, someMethodInfo, arg1Param, arg2Param), instance, arg1Param, arg2Param);
var someDelegate =lambda.Compile();
var myClass = new SomeClass(2);
var arg1 = "yup";
var arg2 = 1;
var result = someDelegate(myClass, arg1, ref arg2);
if(arg2 != 6) throw new Exception("Bad!");
Console.WriteLine("works...");
}
}
The important bit I think is typeof (int).MakeByRefType() .

how to add a method name from Config file to a delegate?

I have to call a method whose name is coming from a configuration file. I can achieve this using Reflection.MethodInfo.Invoke() method. But my scenario is all these methods should be of same signature. Can i implement it using Delegates? but how can i add a method name stored in configuration file to a delegate?
Look at Delegate.CreateDelegate on MSDN. Some of the best docs there!
You can create a re-usable delegate if you wanted to, e.g. given my type:
public class MyClass
{
public void DoSomething(string argument1, int argument2)
{
Console.WriteLine(argument1);
Console.WriteLine(argument2);
}
}
I could do something like:
Action<object, MethodInfo, string, int> action =
(obj, m, arg1, arg2) => m.Invoke(obj, new object[] { arg1, arg2 });
And call it as:
var method = typeof(MyClass).GetMethod("DoSomething");
var instance = new MyClass();
action(instance, method, "Hello", 24);
If you know your method has a return type, you can do that with a System.Func delegate:
public class MyClass
{
public string DoSomething(string argument1, int argument2)
{
return string.Format("{0} {1}", argument1, argument2);
}
}
Func<object, MethodInfo, string, int, string> func =
(obj, m, arg1, arg2) => (string)m.Invoke(obj, new object[] { arg1, arg2 });
string result = func(instance, method, "Hello", 24);

How to pass a function as a parameter in C#?

Is it possible to pass a function as a parameter in C#? I can do it using the Func or Action classes, but this forces me to declare the entire function signature at once. When I try to use Delegate, I get a compile error saying it can't convert a method group to a Delegate.
I'm working on Axial and I'm trying to allow users to call web services. What I'm going for is the ability to create the Visual Studio proxy class and then pass in the generated function. The function signature doesn't matter because the generated code only uses the function name. However, I'd like to pass in the function instead of the name for two reasons: the ability to use the proxy's Url property and a compiler error if the web service doesn't exist or is updated in Visual Studio.
public void AlertIt(object o) {
Axial.DOM.Window.Alert(o.ToString());
}
public void CallAddService() {
object[] param = new object[] { int.Parse(txtA.Text), int.Parse(txtB.Text) };
Axial.ServerScript.CallWebService(new WSProxy.WS().Add, param, AlertIt, AlertIt);
}
class Axial.ServerScript {
public void CallWebService(Delegate method, object[] param, Action<object> successCallback, Action<object> failureCallback) {
// translate to javascript (already working)
}
}
I think what you want is:
static object InvokeMethod(Delegate method, params object[] args){
return method.DynamicInvoke(args);
}
static int Add(int a, int b){
return a + b;
}
static void Test(){
Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}
Prints "9".
Converting a method group, anonymous method or lambda expression to a delegate requires the compiler to know the exact delegate type. However, you could potentially use lambda expressions and captured variables to make this simpler:
public void InvokeMethod(Action action)
{
action();
}
public int Add(int a, int b)
{
return a + b;
}
public void Test()
{
InvokeMethod(() => Add(2, 3));
}
That basically delays invocation in the normal way, but by wrapping the actual call to Add in a plain Action delegate.
If that doesn't fulfil your requirements, perhaps you can tell us a bit more about what you're really trying to achieve.
EDIT: If this is generated code, you can cast to a Func<...> with the right type arguments - assuming there aren't too many. Other than that, there's no real way of just passing in a method group. There's been occasional calls for an "infoof(...)" operator (like typeof but for members) which would give you a MemberInfo, but that doesn't actually exist.
You should have a delegate first
delegate int Operation(int a, int b)
then it becomes:
public void InvokeMethod(Operation method, object target, object param)
{
method((int) target, (int) param);
}
No need for any call to Invoke.
As with dbone I'm unsure why you would need a params[] array. Would you clarify the expanded usage for the params?
Also, I'll have to correct something in your question though, because it will cause a compilation error :p
please have a look at using delegates here is a great example
Delegate Example
why are you using reflection? will there ever be a different number of params? or do you know the method signture will remain constant (also remember C# supports the params[] keyword)
params c#
HTH
Bones
Look at Functional Programming Series by Justin Etheredge.
You should find solution to your problem there.
This is much simple example, to programmer who already familiar with (C/C++/VB.NET/Python)-style pass function by pointer/ref (with C# delegate):
delegate void CALLBACK(String s);
static void Main(string[] args)
{
Get("some string", testfunc);
Util.pause();
}
static void Get(String s, CALLBACK x)
{
x(s);
}
static void testfunc(String s)
{
Console.WriteLine(s);
}
Say If you need to pass the method as parameter as well as you need to catch the return value for further processing . Then the above examples will work fine .
But say if you need to pass a method with void return type then you need to create one more version of the InvokeMethod function.
Check the example below.
private static T retry<T>(Delegate method, params object[] args)
{
for (int i = 0; i <= 3; i++)
{
try
{
return (T)method.DynamicInvoke(args);
}
catch (Exception ex)
{
if (i == 3)
{
logMessage(ex.Message);
}
Console.WriteLine("Retry count " + i);
Thread.Sleep(10);
}
}
return default(T);
}
private static void retry2(Delegate method, params object[] args)
{
for (int i = 0; i <= 3; i++)
{
try
{
method.DynamicInvoke(args);
break;
}
catch (Exception ex)
{
if (i == 3)
{
logMessage(ex.Message);
//return default(T);
}
Console.WriteLine("Retry count " + i);
Thread.Sleep(10);
}
}
}
static bool isSuccess = true;
static void logMessage(string msg)
{
isSuccess = false;
Console.WriteLine(msg);
}
static int Add(int a, int b)
{
return a + b;
}
static void Add2(int a, int b)
{
int c = a + b;
Console.WriteLine(c);
}
static void Main(string[] args)
{
int d = retry<int>(new Func<int, int, int>(Add), 6, 7.7);
Console.Write(" " + d + "\n"+isSuccess);
retry2(new Action<int, int>(Add2), 45, 60);
Console.ReadKey();
}
Something like this ought to work for you:
delegate int MyDelegate(int a, int b);
public int Add(int a, int b) {
return a + b;
}
public void InvokeMethod(Delegate method, object[] param) {
Console.WriteLine(method.DynamicInvoke(param));
}
public Form1() {
InitializeComponent();
InvokeMethod(new MyDelegate(Add), new object[] { 1, 2 });
}
Good luck!

Categories