My code is as follows:
class PropertyRetrievalClass
{
public delegate object getProperty(string input);
public object get_Chart_1(string iput)
{
Console.WriteLine(iput);
return "";
}
public object get_Chart_2(string iput)
{
Console.WriteLine(iput);
return "";
}
public PropertyRetrievalClass() { }
}
public static void Main()
{
int i = 1;
PropertyRetrievalClass obj = new PropertyRetrievalClass();
Delegate del = Delegate.CreateDelegate(typeof(PropertyRetrievalClass), obj, "get_chart_" + i.ToString());
string output= del("asldkl");
}
It is giving me an error saying "error CS0118: 'del' is a 'variable' but is used like a 'method'"
What should I do to use this delegate? I want to call any of "get_chart_1" or "get_chart_2" function and both of them take a string input?
Thanks in advance...
You have two issues in your code.
A Delegate object is not a method, so you need to use a method on the Delegate object to invoke the method it refers
The first argument to CreateDelegate should be the delegate type, not the class containing a method you want to invoke.
Full working example:
public delegate void ParamLess();
class SomeClass
{
public void PrintStuff()
{
Console.WriteLine("stuff");
}
}
internal class Program
{
private static Dictionary<int, int> dict = null;
static void Main()
{
var obj = new SomeClass();
Delegate del = Delegate.CreateDelegate(typeof(ParamLess), obj,
"PrintStuff", false);
del.DynamicInvoke(); // invokes SomeClass.PrintStuff, which prints "stuff"
}
}
In your case, the Main method should look like this:
public static void Main()
{
int i = 1;
PropertyRetrievalClass obj = new PropertyRetrievalClass();
Delegate del = Delegate.CreateDelegate(
typeof(PropertyRetrievalClass.getProperty),
obj,
"get_Chart_" + i.ToString());
string output = (string)del.DynamicInvoke("asldkl");
}
Update
Note that CreateDelegate is case sensitive on the method name, unless you tell it not to.
// this call will fail, get_chart should be get_Chart
Delegate del = Delegate.CreateDelegate(
typeof(PropertyRetrievalClass.getProperty),
obj,
"get_chart_" + i.ToString());
// this call will succeed
Delegate del = Delegate.CreateDelegate(
typeof(PropertyRetrievalClass.getProperty),
obj,
"get_Chart_" + i.ToString());
// this call will succeed, since we tell CreateDelegate to ignore case
Delegate del = Delegate.CreateDelegate(
typeof(PropertyRetrievalClass.getProperty),
obj,
"get_chart_" + i.ToString(),
true);
The other answers have addressed the problem with your code, but I wanted to offer an alternative.
If there are a limited, finite number of methods that your retrieval class is choosing from, and they have the same signatures, this can be done much more efficiently without using reflection:
public int MethodIndex {get;set;}
public static void Main()
{
PropertyRetrievalClass obj = new PropertyRetrievalClass();
Func<string,object> getChartMethod;
switch(MethodIndex)
{
case 1:
getChartMethod = obj.get_chart_1;
break;
case 2:
getChartMethod = obj.get_chart_2;
break;
}
string output= getChartMethod("asldkl");
}
If there were a lot, you could just create an array instead of using a switch. Obviously you could just run the appropriate function directly from the switch, but I assume that the idea is you may want to pass the delegate back to the caller, and a construct like this lets you do that without using reflection, e.g.
public static Func<string,object> GetMethod
{
... just return getChartMethod directly
}
You are using the Delegate class not the delegate keyword.
You cannot call a method on Delegate type. You have to use DynamicInvoke() which is very slowwwwwww.
Try this:
string output = (string) del.DynamicInvoke(new object[]{"asldkl"});
You can only call delegates with method call syntax, if they have a known signature. You need to cast your delegate to the delegate type you defined earlier.
var del = (PropertyRetrievalClass.getProperty)Delegate.CreateDelegate(typeof(PropertyRetrievalClass.getProperty), obj, "get_Chart_" + i.ToString());
You also need to change the first argument to CreateDelegate, because it should be the delegate type. And capitalize the "C" in "get_Chart_".
And then, you will need to cast the returned object to string:
string output= (string) del("asldkl");
Or change the delegate type and the methods to have string as their return type.
Related
I'm working with an C API in C#. In C Methods are passed as parameters and I'm trying to accomplish the same thing in C#.
in C I would call the functions the following way:
LL_SetStatusCb(OnStatusRcv);
LL_SetScanCb(scanCb);
LL_Scan();
Note that the used methods are defined in the following way:
void OnStatusRcv(ll_status_t status)
void scanCb(ll_scan_result_t *result)
In C# the methods are defined in the same way but I don't know how I can pass those methods.
C# equivalent of function pointers are delegates. You can use Func and Action to pass methods as parameters. Func delegate represents method which takes N arguments and returns value, Action delegate represents void method.
Consider this
void (* myFunction)(int parameter)
in C# would be
Action<int>
Please try this code:
create ll_scan_result_t and ll_status_t classes.
class Program
{
delegate void ActionRef<T>(ref T item);
static void Main(string[] args)
{
ll_status_t _status = new ll_status_t();
LL_SetStatusCb(_status, OnStatusRcv);
ll_scan_result_t _scan = new ll_scan_result_t();
LL_SetScanCb(ref _scan);
}
static void LL_SetScanCb(ref ll_scan_result_t status, ActionRef<ll_scan_result_t> getCachedValue)
{
//... do something
}
static void LL_SetStatusCb(ll_status_t result, Action<ll_status_t> getCachedValue)
{
//... do something
}
static void OnStatusRcv(ref ll_scan_result_t sresult)
{
//... do something
}
static void scanCb(ll_status_t s)
{
//... do something
}
}
Use the Func Delegate like below
public class myClass
{
public bool TestMethod(string input)
{
return true;
}
public bool Method1(Func<string, bool> methodName)
{
return true;
}
public void newMthod()
{
Method1(TestMethod);
}
}
In C#, the equivalent to C/C++ function pointers are delegates. A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method that has a compatible signature and return type. You can call the method through the delegate instance.
Here's an example. First, declare a delegate:
public delegate void Del(string message);
Now, Del is a delegate type which can be used to call to any method that returns void and accepts an argument of type string. Now, let's create some method matching the signature and return type of Del:
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
Now, let's create an instance of Del and associate it with DelegateMethod, like this:
Del handler = DelegateMethod;
If you want to call DelegateMethod, you can do it by:
handler("Hello World");
Notice that since Del is a type, you can do something like this:
public static void SomeMethod(Del callback, string callbackParams)
{
callback(callbackParams);
}
Which can be used as:
SomeMethod(handler, "Hello World");
With that said, there are othes ways of working with delegates. You can use Func and Action delegates. Func is a delegate that points to a method that accepts one or more arguments and returns a value, that is, it doesn't return void. Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value (returns void). In other words, you should use Action when your delegate points to a method that returns void.
Here's an example of using an Action delegate:
static void Main(string[] args)
{
Action<string> action = new Action<string>(Display);
action("Hello!!!");
Console.Read(); //Prevents from closing the command line right away.
}
static void Display(string message)
{
Console.WriteLine(message);
}
Therefore, something like
void (* funcPtr)(int) = &someFuncWithAnIntArg;
(*funcPtr)(10);
Is equivalent in C# to
Action<int> funcPtr = new Action<int>(someFuncWithAnIntArg);
funcPtr(10);
And now for a Func delegate:
static void Main(string[] args)
{
Func<int, double> func = new Func<int, double>(CalculateHra);
Console.WriteLine(func(50000));
Console.Read();
}
static double CalculateHra(int basic)
{
return (double)(basic * .4);
}
The syntax for a Func delegate accepting an argument and returning a value is like this Func<TArgument, TOutput> where TArgument is the type of the argument and TOutput is the type of returned value. There are many more types of Func (browse the left tree index) and Action (also browse the left tree index) delegates.
And last, but not least, we have the Predicate delegates which is typically used to search items in a collection or a set of data. Let's define some boilerplate code to explain:
class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
}
Then, let's try it in:
static void Main(string[] args)
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer { Id = 1, FirstName = "Stack" });
customers.Add(new Customer { Id = 2, FirstName = "Overflow" });
Predicate<Customer> pred = x => x.Id == 1;
Customer customer = customers.Find(pred);
Console.WriteLine(customer.FirstName);
Console.Read();
}
The last code snippet will print "Stack". What happened is that the Predicate delegate named prep was used as a search criteria to search in the list customers. Basically, this delegate was run on every element x of the list, and when x.Id == 1 it returns true, false otherwise. The x element where the predicate returned true is returned as the result of the Find method.
is it possible to make generic function in c# that get as input some class and method (of the class) and parameters to the method ( and maybe the result type ) and make instance of that class and call to the function of the class with the parameters and return the result?
Sure.
public class MyClass
{
public class Test
{
public int TestMethod(int a, int b)
{
return a + b;
}
}
public static void Main()
{
int result = ExecuteMethod<Test, int>("TestMethod", 1, 2);
Console.Read();
}
public static TResult ExecuteMethod<TClass, TResult>(string methodName, params object[] parameters)
{
// Instantiate the class (requires a default parameterless constructor for the TClass type)
var instance = Activator.CreateInstance<TClass>();
// Gets method to execute
var method = typeof(TClass).GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
// Executes and returns result
return (TResult)method.Invoke(instance, parameters);
}
}
Unless Reflection is your absolute option, use one of the following delegates:
Action<T>: Will let you execute a method that does not return a value. There are several overloads that will let you pass in additional arguments.
Func<TResult>: Will let you execute a method that returns a result of type TResult. There are more overloads that will let you pass in additional arguments. They all follow the syntax Func<T1, T2, T3, TResult> and so on.
And finally, you can define your own delegate.
Yes it's possible. You can do that with reflection.
Here you have a few useful links
Create an instance with reflection
How to invoke method with parameters
Here's how you create an instance of a class using reflection and then call a method on that class.
Assuming you have a class:
public class MyType
{
public void DoSomething()
{
// do stuff here
}
}
You could do the following:
Type instanceType = Type.GetType("MyType");
object instance = Activator.CreateInstance(instanceType);
MethodInfo method = instanceType.GetMethod("MethodName");
object returnValue = method.Invoke(instance, new object[] { /* paramaters go here */ });
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 a DynamicObject or a more general delegate, with the specific Type of delegate using CompiledExpressions (source).
using System.Dynamic you can create an invokable object:
public class AnyInvokeObject:DynamicObject{
Func<object[],object> _func;
public AnyInvokeObject(Func<object[],object> func){
_func = func;
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result){
result = _func(args);
return true;
}
}
Then in your sample:
var tmpObj = new AnyInvokeObject(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;
});
methodParams[i] = Dynamic.CoerceToDelegate(tmpObj, paramInfo.ParameterType);
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
var connection = $.hubConnection();
var yourHubProxy = connection.createHubProxy('yourHub');
yourHubProxy.on('addMessageToConsole', function (message) {
console.log(message);
});
and on the server
public class YourHub : Hub
{
public void SendMessage(string message)
{
Clients.All.addMessageToConsole(message);
}
}
See here for more examples.
How about a solution without delegates?
(warning: rampant pseudocode)
class AbstractServerToClientMessage {
public virtual string ToJSON();
}
class OnNewObjectMessage: AbstractServerToClientMessage {...}
class OnSomethingElseHappenedMessage: AbstractServerToClientMessage {...}
void NotifyClient(AbstractServerToClientMessage message)
event OnNewObject;
event OnSomethingElseHappened;
void notifyAboutNewObjects() {
...
OnNewObject += NotifyClient;
...
}
void AddNewObject(SomeObject obj) {
OnNewObjectMessage message(obj);
OnNewObject(message);
// actually add the object
}
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.
I have the following code:
class Program
{
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
// works
Func<IEnumerable<int>> static_delegate = new Func<IEnumerable<int>>(SomeMethod<String>);
MethodInfo mi = this.GetType().GetMethod("SomeMethod").MakeGenericMethod(new Type[] { typeof(String) });
// throws ArgumentException: Error binding to target method
Func<IEnumerable<int>> reflection_delgate = (Func<IEnumerable<int>>)Delegate.CreateDelegate(typeof(Func<IEnumerable<int>>), mi);
}
public IEnumerable<int> SomeMethod<T>()
{
return new int[0];
}
}
Why can't I create a delegate to my generic method? I know I could just use mi.Invoke(this, null), but since I'm going to want to execute SomeMethod potentially several million times, I'd like to be able to create a delegate and cache it as a small optimization.
You method isn't a static method, so you need to use:
Func<IEnumerable<int>> reflection_delgate = (Func<IEnumerable<int>>)Delegate.CreateDelegate(typeof(Func<IEnumerable<int>>), this, mi);
Passing "this" to the second argument will allow the method to be bound to the instance method on the current object...
I have an implementation building a delegate handler collection.
public class DelegateHandler
{
internal delegate object delegateMethod(object args);
public IntPtr PublishAsyncMethod(MethodInfo method, MethodInfo callback)
{
RuntimeMethodHandle rt;
try
{
rt = method.MethodHandle;
delegateMethod dMethod = (delegateMethod)Delegate.CreateDelegate
(typeof(delegateMethod), method.ReflectedType, method, true);
AsyncCallback callBack = (AsyncCallback)Delegate.CreateDelegate
(typeof(AsyncCallback), method.ReflectedType, callback, true);
handlers[rt.Value] = new DelegateStruct(dMethod, callBack);
return rt.Value;
}
catch (System.ArgumentException ArgEx)
{
Console.WriteLine("*****: " + ArgEx.Source);
Console.WriteLine("*****: " + ArgEx.InnerException);
Console.WriteLine("*****: " + ArgEx.Message);
}
return new IntPtr(-1);
}
}
I publish using the following:
ptr = DelegateHandler.Io.PublishAsyncMethod(
this.GetType().GetMethod("InitializeComponents"),
this.GetType().GetMethod("Components_Initialized"));
And the method I'm creating a delegate from:
public void InitializeComponents(object args)
{
// do stuff;
}
And the callback method:
public void Components_Initialized(IAsyncResult iaRes)
{
// do stuff;
}
Now, I've also already looked at this to get an idea of what I might be doing wrong. The CreateDelegate(...) is causing me to receive:
*****: mscorlib
*****:
*****: Error binding to target method.
What is wrong? The methods reside in a different, non-static public class. Any help would be greatly appreciated.
NOTE: These methods will have parameters and return values. As I understand Action, and Action<T>, this would not be an option.
There are 2 problems.
First, you are passing incorrect arguments to CreateDelegate. Since you are binding to instance methods, you need to pass the instance to which the delegates will be bound, but you are passing method.ReflectedType instead of a reference to an object of the class that declares InitializeComponents and Components_Initialized.
Second, the signature of InitializeComponents does not match the declaration of delegate dMethod. The delegate has an object return type yet InitializeComponents returns void.
The following should work:
// return type changed to void to match target.
internal delegate void delegateMethod(object args);
// obj parameter added
public static void PublishAsyncMethod(object obj, MethodInfo method, MethodInfo callback)
{
delegateMethod dMethod = (delegateMethod)Delegate.CreateDelegate
(typeof(delegateMethod), obj, method, true);
AsyncCallback callBack = (AsyncCallback)Delegate.CreateDelegate
(typeof(AsyncCallback), obj, callback);
}
DelegateHandler.PublishAsyncMethod(
this, // pass this pointer needed to bind instance methods to delegates.
this.GetType().GetMethod("InitializeComponents"),
this.GetType().GetMethod("Components_Initialized"));