Store reference to method to be called later with different parameters - c#

I need to be able to have ONE variable type store references to different methods, then call them later with different parameters, and have them return something. The methods will each have different parameter types and output types. I've tried delegates, actions and Func.
Pseudo code example below
public void Open(String directory){
File.Open(Directory);
}
public string ChangeVolume(int volume){
//Code to change volume
//return the new volume
}
public static void Main{
MyVaribleType var1 = Open;
myVaribleType var2 = ChangeVolume;
var1("C:\Windows");
Console.WriteLine(var2(100) );
}
How would I accomplish this with a single variable type?

You can hold references to the methods in collection of MethodInfo class provided by reflection APIs. To be able to call these methods you will also need to keep the references of the objects on which you want to call these methods. You can use reflection itself to invoke these methods. Reflection is slow so you can use this method only if you don't have high performance requirements.

You can't do it quite as you want to: the two methods have different signatures as #Mephy noted. You can do it using delegates, though:
public delegate FileStream OpenFileHandler(string filePath);
public delegate string ChangeVolumeHandler(FileStream stream, int volume);
class Program
{
private static FileStream Open(string filePath)
{
return File.Open(filePath, FileMode.OpenOrCreate);
}
private static string ChangeVolume(FileStream stream, int volume)
{
return "Done! Honest!";
}
static void Main(string[] args)
{
OpenFileHandler ofh = Program.Open;
ChangeVolumeHandler cvh = Program.ChangeVolume;
FileStream stream = ofh("path");
string xyzzy = cvh(stream, 100);
}
}
I'm not sure why you'd want to, but I assume that this is a rather more complex requirement that you've shown, so fine.
Note that in addition to having to use two delegates, you aloso have to pass each the items it needs to work on and that it creates (e.g. the FileStream object).

You can use an ExpandoObject:
dynamic d = new ExpandoObject();
d.ChangeVolume = new Func<int, string>(ChangeVolume);
and then call it thusly:
var result = d.ChangeVolume(volume); //ChangeVolume is type-checked at runtime.
or simply write the logic into the new dynamic property directly:
d.ChangeVolume = new Func<int, string>(x => (x * x).ToString()); // or whatever

Related

Why does a lambda expression preserve enclosing scope variable values after method terminates?

I was under the impression that lambda expression contexts in C# contain references to the variables of the parent function scope that are used in them. Consider:
public class Test
{
private static System.Action<int> del;
public static void test(){
int i = 100500;
del = a => System.Console.WriteLine("param = {0}, i = {1}", a, i);
del(1);
i = 10;
del(1);
}
public static void Main()
{
test();
}
}
outputs
param = 1, i = 100500
param = 1, i = 10
However, if this was true, the following would be illegal, because the lambda context would reference a local variable that went out of scope:
public class Test
{
private static System.Action<int> del;
public static void test(){
int i = 100500;
del = a => System.Console.WriteLine("param = {0}, i = {1}", a, i);
}
public static void Main()
{
test();
del(1);
}
}
However, this compiles, runs and outputs
param = 1, i = 100500
Which means that either something weird is going on, or the context keeps values of the local variables, not references to them. But if this was true, it would have to update them on every lambda invokation, and I don't see how that would work when the original variables go out of scope. Also, it seems that this could incur an overhead when dealing with large value types.
I know that, for example, in C++, this is UB (confirmed in answer to this question).
The question is, is this well-defined behaviour in C#? (I think C# does have some UB, or at least some IB, right?)
If it is well-defined, how and why does this actually work? (implementation logic would be interesting)
The concept of closures as they relate to the lambda syntax in C# is a very large topic and too large for me to cover everything in just this answer but let's try to answer the specific question here at least. The actual answer is at the bottom, the rest between is background needed to understand the answer.
What happens when the compiler tries to compile a method using anonymous methods is that it rewrites the method to some extent.
Basically, a new class is generated and the anonymous method is lifted into this class. It's given a name, albeit an internal one, so for the compiler it sort of transitions from an anonymous method into a named method. You, however, doesn't have to know or handle that name.
Any variables that this method required, variables that was declared besides the anonymous method, but in the same method that used/declared the anonymous method, will be lifted as well, and then all usages of those variables is rewritten.
There's a couple of methods involved here now so it becomes hard to read the above text so instead let's do an example:
public Func<int, int> Test1()
{
int a = 42;
return value => a + value;
}
This method is rewritten to something like this:
public Func<int, int> Test1()
{
var dummy = new <>c__DisplayClass1();
dummy.a = 42;
return dummy.<Test1>b__0;
}
internal class <>c__DisplayClass1
{
public int a;
public int <Test1>b__0(int value)
{
return a + value;
}
}
The compiler can handle all these funky names (and yes, they really are named with all the brackets like that) because it refers to things with id's and object references, the names are no longer an issue for the compiler. You, however, can never declare a class or a method with those names so there's no risk of the compiler generating a class that just happens to already exist.
Here's a LINQPad example that shows that a class I declared, although with less brackets in its names, looks identical to the one generated by the compiler:
void Main()
{
var f1 = Test1();
f1(10).Dump();
f1.Dump();
var f2 = Test2();
f2(10).Dump();
f2.Dump();
}
public Func<int, int> Test1()
{
int a = 42;
return value => a + value;
}
public Func<int, int> Test2()
{
var dummy = new __c__DisplayClass1();
dummy.a = 42;
return dummy._Test2_b__0;
}
public class __c__DisplayClass1
{
public int a;
public int _Test2_b__0(int value)
{
return a + value;
}
}
output:
If you look at the screenshot above you notice two things for each delegate variable, a Method property, and a Target property.
When calling the method, it is called with a this reference referring to the Target object. A delegate thus captures two things: Which method to call, and the object on which to call it.
So basically, that object of that generated class survives as part of the delegate because it is the target of the method.
With all that in mind, let's look at your question:
Why does a lambda expression preserve enclosing scope variable values after method terminates?
A: If the lambda survives, all the captured variables survive as well because they're no longer local variables of the method they were declared in. Instead they were lifted onto a new object that also has the lambda method, and thus "follows" the lambda everywhere it goes.

How to construct a call to a method using dynamic

Hi I have a namespace with a lot of classes and all of them has a method Destroy(int id)
I want to call that method using dynamic word.
Here is my example:
public bool DeleteElement<T>(T tElement)
{
Type t = typeof(T);
dynamic element = tElement;
var id = element.Id;
//until here everything is fine
//here I want to say
(namespace).myClassName.Destroy(id);
//the name of myClassName is like t.ToString()
}
I can avoid namespace including a using at the top. The idea is to call that static method using dynamic, not Reflection, please see that Destroy is a static method of T. I need something like this T.Destroy(id)
If Destroy(int id) is a static method, couldn't you create an instance method that would call the static one?
public void Destroy()
{
ThisClass.Destroy(this.Id);
}
You could then define an IDestroyable interface implemented by all these classes:
interface IDestroyable { void Destroy(); }
And then modify your DeleteElement method as follows:
public bool DeleteElement<T>(T tElement) where T : IDestroyable
{
tElement.Destroy();
}
No need to use dynamic here... Actually, using dynamic in this situation is often an indication of bad design. It's quite rare to actually need dynamic except in the scenarios for which it was created (e.g. interop with dynamic languages)
(If the classes are generated but they have the partial modifier, you can declare the new method in another file that is not touched by the generator)
EDIT: if the classes are generated and are not partial, you can't modify them... So another solution would be to use reflection; I know you want to avoid that (for performance reasons I assume), but you can limit the performance impact by doing the reflection only once for each type: you just need to create and cache a delegate for each type.
class DestroyHelper<T>
{
static readonly Action<int> _destroy;
static readonly Func<T, int> _getId;
static DestroyHelper()
{
var destroyMethod = typeof(T).GetMethod("Destroy", BindingFlags.Static | BindingFlags.Public);
_destroy = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), destroyMethod);
var getIdMethod = typeof(T).GetProperty("Id").GetGetMethod();
_getId = (Func<T, int>)Delegate.CreateDelegate(typeof(Func<T, int>), getIdMethod);
}
public static void Destroy(T element)
{
_destroy(_getId(element));
}
}

how to pass function to different DLL included in project as reference

I have referenced one DLL (I have source code of this) say Dll_A in which there is a function
private void uploadPic(int a)
In my main project, I have a function say
private void passMe(int b)
{
}
I need to pass the above function (passMe) to uploadPic function in Dll_A, how can I do that? Is it possible?
I am able to use functions of the Dll_A from my main project, so instantiating isn't a problem, I just need a way to pass function.
===
Thanks, giving it a try. If some can edit code below
//code in main project picbackman.cs
public delegate void delObj(int v);
private void uploadSome(string path, string fName, string str)
{
delObj del1 = new delObj(updatePValue);
UploadFileResponse response = boxProvider1.UploadFiles(args1, folderString, ((Picbackman.BoxProvider.delObj)( del1)));
}
//code in different dll which is referenced in main project //Dll_A
public delegate void delObj(int v);
public UploadFileResponse UploadFiles(string[] filePathes,string folderId, delObj d)
{}
First of all your method will need to accept a delegate as one of it's parameters. That would be something like
private void uploadPic(Action<int> func,int a){
//at some point do func(someInt);
}
at another point declare anothe method or function
public class someClasse {
public vois passMe(int b){
...
}
}
First of all notice that the access modifier has changed. if they are not in the same class you will need to be able to access one from the other so they can't both be private and since they are in different assemblies internal won't work either.
when you need the delegate do like this
var obj = new someClass();
var myInt = 5; //or whatever the value is
uploadPic(obj.passMe,myInt);
notice that the method is used with out arguments. When using a method without arguments the compiler will try and convert it to a suitable delegate.
I'd recommend you not to use delegate but stick with Func/Action they are delegates but more generic
public delegate void DelObj1();
public delegate void DelObj2()
public void F(){};
var del1 = new DelObj1(F);
var del2 = new DelObj2(F);
you can't pass a del1 where a DelObj2 is needed even though you use the same method for each. You will not have that issue if you use Action/Function
Action del1 = F;
Action del2 = F;
The reason is that DelObj1 and DelObj2 are two distinct classes with the same base class Ie they are siblings in the type tree. Using Action the type is the same for both del1 and del2
You should have a look at Delegates.
From the documentation:
A delegate is a type that references a method. Once a delegate is
assigned a method, it behaves exactly like that method. The delegate
method can be used like any other method, with parameters and a return
value
and
Delegates allow methods to be passed as parameters
So in your case you should be able to do something like this:
// define the delegate
public delegate int PictureDelegate(int value)
// define your passMe function (in the class MyClass for example)
public int passMe(int value)
{
return value + 1;
}
// when you want to use it
MyClass myInstance = new MyClass();
PictureDelegate passFunc = new PictureDelegate(myInstance.passMe);
myDll.uploadPic(passFunc, 12);

Can methods be called via an array in C#?

I have a program that will need to run different methods depending on what I want it to talk to, and I want to know if there is a way to store some sort of method pointer or something of that sort in an array. So I want an array where each element would be something like this:
[Boolean: Do_this?] [Function_pointer] [Data to pass to the function]
So basically, I can put this into a for loop and not call each function individually. Another block of code would fill in the Boolean of whether to run this function or not, and then my for loop would go through and run the function with its appropriate data if the Boolean is true.
I know delegates are similar to function pointers, but if that is the answer here, I'm not entirely sure how I would construct what I want to construct.
Is this possible in C#?
Sure is, although, to do it this way, you need all methods to have the same signature:
Lets say you had two methods:
public int Moop(string s){ return 1; }
public int Moop2(string s){ return 2; }
You could do:
var funcs = new Func<string, int>[]{ Moop, Moop2 };
And to call:
var val = funcs[0]("hello");
You could declare a specific object type to hold in a delegate, a flag that indicates whether to do that or now and the data. Note that what you are describing is very similar to events as they are also defined by a callback and some event data.
The skeletal model would look something like this, assuming all methods you want to call have the same signature (you can work around that, if you need a whole bunch of various signatures by using reflection):
// This reflects the signature of the methods you want to call
delegate void theFunction(ActionData data);
class ActionData
{
// put whatever data you would want to pass
// to the functions in this wrapper
}
class Action
{
public Action(theFunction action, ActionData data, bool doIt)
{
this.action = action;
this.data = data;
this.doIt = doIt;
}
public bool doIt
{
get;
set;
}
public ActionData data
{
get;
set;
}
public theFunction action
{
get;
set;
}
public void run()
{
if (doIt)
action(data);
}
}
And a regular use case would look something like this:
class Program
{
static void someMethod(ActionData data)
{
Console.WriteLine("SUP");
}
static void Main(string[] args)
{
Action[] actions = new Action[] {
new Action(Program.someMethod, new ActionData(), true)
};
foreach(Action a in actions)
a.run();
}
}
Yes, you can.
If all your functions share the same signature you might want to store delegates in your collection, otherwise I would go for System.Reflection.MethodInfo, which you can use later on by calling Invoke method. Parameters would be stored as array of objects - that's what Invoke expects.
If using reflection is too slow you can use Reflection.Emit to generate dynamic methods at runtime.
I would just create a List<Action>. Action is a delegate that takes no parameters and returns no results. You can use currying and lambdas such that the actual actions can call a method that has parameters. In the case where you don't actually want to run it, just don't add it to the list in the first place (or add an action that does nothing I guess).
To add an item it might look something like:
list.Add(() => someobject.someMethod(firstArgument, secondArgument));
list.Add(() => anotherObject.anotherMethod(oneArgument));
Then you can just run all of the actions when you want to:
foreach(Action action in list)
{
action();
}
This is exactly what you would use delegates for. Delegates are, more or less, type-checked function pointers. You can create some delegates and put them into an array.
Func<int, int> [] funcs = new Func<int,int>[] { x => 2 * x, x => x * x };
foreach(var fn in funcs)
{
Console.WriteLine(fn(3));
Console.WriteLine(fn(8));
}

Call/Invoke a method based on a string value contained in an array [duplicate]

This question already has answers here:
Calling a function from a string in C#
(5 answers)
Closed 1 year ago.
I have a struct-array that contains details of different reports that can be run. Each report calls a different method and currently the program has to manually check the selected report value to specifically call the appropriate method.
I would like to store the method name in the struct-array and then have program invoke that method when there is match. Is this possible?
Currently:
if (this.cboSelectReport.Text == "Daily_Unload")
{
reportDailyUnload();
}
Ideally:
if(this.cboSelectReport.Text == MyArray[i].Name)
{
something(MyArray[i].MethodName);
}
UPDATE
I tired a number of the suggestions below and none of them worked. They didn't work probably due to how I have my program structured.
You can do it using reflection, but IMO it is too fragile: it introduces an invisible dependency on the name of the method that you call.
// Assuming that the method is static, you can access it like this:
var namedReportMethod = "MyReport1";
var reportMethod = typeof(ReporterClass).GetMethod(namedReportMethod);
var res = reportMethod.Invoke(null, new object[] {reportArg1, reportArg2});
A better approach would be to define a delegate based on your method, and store it in the struct/class instead of the method name.
delegate void ReportDelegate(int param1, string param2);
class Runner {
public static void RunReport(ReportDelegate rd) {
rd(1, "hello");
}
}
class Test {
static void TestReport(int a, string b) {
// ....
}
public static void Main(string[] args) {
Runner.RunReport(TestReport);
}
}
Instead of defining your own delegate types, you can use pre-defined ones based on Action<T1,T2,...> or Func<T1,T2,R>, depending on your need to return values from the reports.
Rather than storing the method name, you could store a delegate:
struct ReportInfo
{
public string Name { get; set; }
public Action Method { get; set; }
}
//...
MyArray[0] = new ReportInfo { Name = "Daily_Unload", Action = this.reportDailyUnload };
//...
if(this.cboSelectReport.Text == MyArray[i].Name)
{
MyArray[i].Method.Invoke();
}
Most people seem to prefer the alternative syntax where you can invoke a delegate as if it were a method, using a list of arguments in parentheses. I tend to avoid this, because it can be ambiguous whether the thing being invoked is a method or a delegate:
MyArray[i].Method();
In this case, we're invoking the delegate that is referred to by the Method property, but this code could also represent a call to a method called "Method". Confusing.
As for me, supporting simple switch is much easier than dealing with reflection, array of method names or delegates, and invoking that stuff:
switch (reportType)
{
case "Daily_Unload":
ReportDailyUnload();
break;
// ...
}
If all the methods share the same signature, one way would be to cache a delegate:
// initialize, maybe in a constructor
Dictionary<string, Action> nameDelegateMapping = new Dictionary<string, Action>();
// setup the delegates
nameDelegateMapping.Add("Daily_Unload", reportDailyUnload);
// ... add more methods here.
// later
string methodName = this.cboSelectReport.Text;
Action action;
if (nameDelegateMapping.TryGetValue(methodName, out action))
{
action();
}
else
{
// tell user the method does not exist.
}
Yes, what you are talking about is reflection. Here is an article on how to invoke a method. There is a lot you can find on reflection using google.
Add a delegate property to your struct (e.g. of type Action) then just invoke this delegate when you need it. Just set this property to the method you want to call when instantiating the struct instances.
Using a delegate and dictionary<string, delegate>
void Main()
{
var reports = new Dictionary<string, Report>
{
{"Daily_Unload", ReportDailyUnLoad}
};
var report = "Daily_Unload";
reports[report]();
}
delegate string Report();
string ReportDailyUnLoad()
{
return "daily unload report";
}

Categories

Resources