As you can see in the code below, I have declared an Action<> object as a variable.
Would anybody please let me know why this action method delegate behaves like a static method?
Why does it return true in the following code?
Code:
public static void Main(string[] args)
{
Action<string> actionMethod = s => { Console.WriteLine("My Name is " + s); };
Console.WriteLine(actionMethod.Method.IsStatic);
Console.Read();
}
Output:
This is most likely because there are no closures, for example:
int age = 25;
Action<string> withClosure = s => Console.WriteLine("My name is {0} and I am {1} years old", s, age);
Action<string> withoutClosure = s => Console.WriteLine("My name is {0}", s);
Console.WriteLine(withClosure.Method.IsStatic);
Console.WriteLine(withoutClosure.Method.IsStatic);
This will output false for withClosure and true for withoutClosure.
When you use a lambda expression, the compiler creates a little class to contain your method, this would compile to something like the following (the actual implementation most likely varies slightly):
private class <Main>b__0
{
public int age;
public void withClosure(string s)
{
Console.WriteLine("My name is {0} and I am {1} years old", s, age)
}
}
private static class <Main>b__1
{
public static void withoutClosure(string s)
{
Console.WriteLine("My name is {0}", s)
}
}
public static void Main()
{
var b__0 = new <Main>b__0();
b__0.age = 25;
Action<string> withClosure = b__0.withClosure;
Action<string> withoutClosure = <Main>b__1.withoutClosure;
Console.WriteLine(withClosure.Method.IsStatic);
Console.WriteLine(withoutClosure.Method.IsStatic);
}
You can see the resulting Action<string> instances actually point to methods on these generated classes.
The "action method" is static only as a side effect of the implementation. This is a case of an anonymous method with no captured variables. Since there are no captured variables, the method has no additional lifetime requirements beyond those for local variables in general. If it did reference other local variables, its lifetime extends to the lifetime of those other variables (see sec. L.1.7, Local variables, and sec. N.15.5.1, Captured outer variables, in the C# 5.0 specification).
Note that the C# specification only talks about anonymous methods being converted to "expression trees", not "anonymous classes". While the expression tree could be represented as additional C# classes, for example, in the Microsoft compiler, this implementation is not required (as acknowledged by sec. M.5.3 in the C# 5.0 specification). Therefore, it is undefined whether the anonymous function is static or not. Moreover, section K.6 leaves much open as to the details of expression trees.
Delegate caching behavior was changed in Roslyn. Previously, as stated, any lambda expression which didn't capture variables was compiled into a static method at the call site. Roslyn changed this behavior. Now, any lambda, which captures variables or not, is transformed into a display class:
Given this example:
public class C
{
public void M()
{
var x = 5;
Action<int> action = y => Console.WriteLine(y);
}
}
Native compiler output:
public class C
{
[CompilerGenerated]
private static Action<int> CS$<>9__CachedAnonymousMethodDelegate1;
public void M()
{
if (C.CS$<>9__CachedAnonymousMethodDelegate1 == null)
{
C.CS$<>9__CachedAnonymousMethodDelegate1 = new Action<int>(C.<M>b__0);
}
Action<int> arg_1D_0 = C.CS$<>9__CachedAnonymousMethodDelegate1;
}
[CompilerGenerated]
private static void <M>b__0(int y)
{
Console.WriteLine(y);
}
}
Roslyn:
public class C
{
[CompilerGenerated]
private sealed class <>c__DisplayClass0
{
public static readonly C.<>c__DisplayClass0 CS$<>9__inst;
public static Action<int> CS$<>9__CachedAnonymousMethodDelegate2;
static <>c__DisplayClass0()
{
// Note: this type is marked as 'beforefieldinit'.
C.<>c__DisplayClass0.CS$<>9__inst = new C.<>c__DisplayClass0();
}
internal void <M>b__1(int y)
{
Console.WriteLine(y);
}
}
public void M()
{
Action<int> arg_22_0;
if (arg_22_0 = C.
<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 == null)
{
C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 =
new Action<int>(C.<>c__DisplayClass0.CS$<>9__inst.<M>b__1);
}
}
}
Delegate caching behavior changes in Roslyn talks about why this change was made.
As of C# 6, this will always default to instance methods now, and will never be static (so actionMethod.Method.IsStatic will always be false).
See here: Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6?
and here: Difference in CSC and Roslyn compiler's static lambda expression evaluation?
The method has no closures and also references a static method itself (Console.WriteLine), so I would expect it to be static. The method will declare an enclosing anonymous type for a closure, but in this instance it is not required.
Related
I have several methods all with the same parameter types and return values but different names and blocks. I want to pass the name of the method to run to another method that will invoke the passed method.
public int Method1(string)
{
// Do something
return myInt;
}
public int Method2(string)
{
// Do something different
return myInt;
}
public bool RunTheMethod([Method Name passed in here] myMethodName)
{
// Do stuff
int i = myMethodName("My String");
// Do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
This code does not work but this is what I am trying to do. What I don't understand is how to write the RunTheMethod code since I need to define the parameter.
You can use the Func delegate in .NET 3.5 as the parameter in your RunTheMethod method. The Func delegate allows you to specify a method that takes a number of parameters of a specific type and returns a single argument of a specific type. Here is an example that should work:
public class Class1
{
public int Method1(string input)
{
//... do something
return 0;
}
public int Method2(string input)
{
//... do something different
return 1;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
//... do stuff
int i = myMethodName("My String");
//... do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
}
You need to use a delegate. In this case all your methods take a string parameter and return an int - this is most simply represented by the Func<string, int> delegate1. So your code can become correct with as simple a change as this:
public bool RunTheMethod(Func<string, int> myMethodName)
{
// ... do stuff
int i = myMethodName("My String");
// ... do more stuff
return true;
}
Delegates have a lot more power than this, admittedly. For example, with C# you can create a delegate from a lambda expression, so you could invoke your method this way:
RunTheMethod(x => x.Length);
That will create an anonymous function like this:
// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
return x.Length;
}
and then pass that delegate to the RunTheMethod method.
You can use delegates for event subscriptions, asynchronous execution, callbacks - all kinds of things. It's well worth reading up on them, particularly if you want to use LINQ. I have an article which is mostly about the differences between delegates and events, but you may find it useful anyway.
1 This is just based on the generic Func<T, TResult> delegate type in the framework; you could easily declare your own:
public delegate int MyDelegateType(string value)
and then make the parameter be of type MyDelegateType instead.
From OP's example:
public static int Method1(string mystring)
{
return 1;
}
public static int Method2(string mystring)
{
return 2;
}
You can try Action Delegate! And then call your method using
public bool RunTheMethod(Action myMethodName)
{
myMethodName(); // note: the return value got discarded
return true;
}
RunTheMethod(() => Method1("MyString1"));
Or
public static object InvokeMethod(Delegate method, params object[] args)
{
return method.DynamicInvoke(args);
}
Then simply call method
Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));
Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
In order to provide a clear and complete answer, I'm going to start from the very beginning before showing three possible solutions.
A brief introduction
All .NET languages (such as C#, F#, and Visual Basic) run on top of the Common Language Runtime (CLR), which is a VM that runs code in the Common Intermediate Language (CIL), which is way higher level than machine code. It follows that methods aren't Assembly subroutines, nor are they values, unlike functional languages and JavaScript; rather, they're symbols that CLR recognizes. Not being values, they cannot be passed as a parameter. That's why there's a special tool in .NET. That is, delegates.
What's a delegate?
A delegate represents a handle to a method (the term handle is to be preferred over pointer as the latter would be an implementation detail). Since a method is not a value, there has to be a special class in .NET, namely Delegate, which wraps up any method. What makes it special is that, like very few classes, it needs to be implemented by the CLR itself and couldn't be simply written as a class in a .NET language.
Three different solutions, the same underlying concept
The type–unsafe way
Using the Delegate special class directly.
Example:
static void MyMethod()
{
Console.WriteLine("I was called by the Delegate special class!");
}
static void CallAnyMethod(Delegate yourMethod)
{
yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}
static void Main()
{
CallAnyMethod(MyMethod);
}
The drawback here is your code being type–unsafe, allowing arguments to be passed dynamically, with no constraints.
The custom way
Besides the Delegate special class, the concept of delegates spreads to custom delegates, which are declarations of methods preceded by the delegate keyword. They are type–checked the same way as “normal” method invocations, making for type-safe code.
Example:
delegate void PrintDelegate(string prompt);
static void PrintSomewhere(PrintDelegate print, string prompt)
{
print(prompt);
}
static void PrintOnConsole(string prompt)
{
Console.WriteLine(prompt);
}
static void PrintOnScreen(string prompt)
{
MessageBox.Show(prompt);
}
static void Main()
{
PrintSomewhere(PrintOnConsole, "Press a key to get a message");
Console.Read();
PrintSomewhere(PrintOnScreen, "Hello world");
}
The standard library's way
Alternatively, you can stick with a delegate that's part of the .NET Standard:
Action wraps up a parameterless void method;
Action<T1> wraps up a void method with one parameter of type T1;
Action<T1, T2> wraps up a void method with two parameters of types T1 and T2, respectively,
and so forth;
Func<TR> wraps up a parameterless function with TR return type;
Func<T1, TR> wraps up a function with TR return type and with one parameter of type T1;
Func<T1, T2, TR> wraps up a function with TR return type and with two parameters of types T1 and T2, respectively;
and so forth.
However, bear in mind that by using predefined delegates like these, parameter names won't be self-describing, nor is the name of the delegate type meaningful as to what instances are supposed to do. Therefore, refrain from using them in contexts where their purpose is not absolutely self-evident.
The latter solution is the one most people posted. I'm also mentioning it in my answer for the sake of completeness.
The solution involves Delegates, which are used to store methods to call. Define a method taking a delegate as an argument,
public static T Runner<T>(Func<T> funcToRun)
{
// Do stuff before running function as normal
return funcToRun();
}
Then pass the delegate on the call site:
var returnValue = Runner(() => GetUser(99));
You should use a Func<string, int> delegate, that represents a function taking a string argument and returning an int value:
public bool RunTheMethod(Func<string, int> myMethod)
{
// Do stuff
myMethod.Invoke("My String");
// Do stuff
return true;
}
Then invoke it this way:
public bool Test()
{
return RunTheMethod(Method1);
}
While the accepted answer is absolutely correct, I would like to provide an additional method.
I ended up here after doing my own searching for a solution to a similar question.
I am building a plugin driven framework, and as part of it I wanted people to be able to add menu items to the applications menu to a generic list without exposing an actual Menu object because the framework may deploy on other platforms that don't have Menu UI objects. Adding general info about the menu is easy enough, but allowing the plugin developer enough liberty to create the callback for when the menu is clicked was proving to be a pain. Until it dawned on me that I was trying to re-invent the wheel and normal menus call and trigger the callback from events!
So the solution, as simple as it sounds once you realize it, eluded me until now.
Just create separate classes for each of your current methods, inherited from a base if you must, and just add an event handler to each.
Here is an example Which can help you better to understand how to pass a function as a parameter.
Suppose you have Parent page and you want to open a child popup window. In the parent page there is a textbox that should be filled basing on child popup textbox.
Here you need to create a delegate.
Parent.cs
// declaration of delegates
public delegate void FillName(String FirstName);
Now create a function which will fill your textbox and function should map delegates
//parameters
public void Getname(String ThisName)
{
txtname.Text=ThisName;
}
Now on button click you need to open a Child popup window.
private void button1_Click(object sender, RoutedEventArgs e)
{
ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor
p.Show();
}
IN ChildPopUp constructor you need to create parameter of 'delegate type' of parent //page
ChildPopUp.cs
public Parent.FillName obj;
public PopUp(Parent.FillName objTMP)//parameter as deligate type
{
obj = objTMP;
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
obj(txtFirstName.Text);
// Getname() function will call automatically here
this.DialogResult = true;
}
If you want to pass Method as parameter, use:
using System;
public void Method1()
{
CallingMethod(CalledMethod);
}
public void CallingMethod(Action method)
{
method(); // This will call the method that has been passed as parameter
}
public void CalledMethod()
{
Console.WriteLine("This method is called by passing it as a parameter");
}
If the method passed needs to take one argument and return a value, Func is the best way to go. Here is an example.
public int Method1(string)
{
// Do something
return 6;
}
public int Method2(string)
{
// Do something different
return 5;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
// Do stuff
int i = myMethodName("My String");
Console.WriteLine(i); // This is just in place of the "Do more stuff"
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
Read the docs here
However, if your method that is passed as a parameter does not return anything, you can also use Action. It supports up to 16 paramaters for the passed method. Here is an example.
public int MethodToBeCalled(string name, int age)
{
Console.WriteLine(name + "'s age is" + age);
}
public bool RunTheMethod(Action<string, int> myMethodName)
{
// Do stuff
myMethodName("bob", 32); // Expected output: "bob's age is 32"
return true;
}
public bool Test()
{
return RunTheMethod(MethodToBeCalled);
}
Read the documentation here
Here is an example without a parameter:
http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
with params:
http://www.daniweb.com/forums/thread98148.html#
you basically pass in an array of objects along with name of method. you then use both with the Invoke method.
params Object[] parameters
class PersonDB
{
string[] list = { "John", "Sam", "Dave" };
public void Process(ProcessPersonDelegate f)
{
foreach(string s in list) f(s);
}
}
The second class is Client, which will use the storage class. It has a Main method that creates an instance of PersonDB, and it calls that object’s Process method with a method that is defined in the Client class.
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
I don't know who might need this, but in case you're unsure how to send a lambda with a delegate, when the function using the delegate doesn't need to insert any params in there you just need the return value.
SO you can also do this:
public int DoStuff(string stuff)
{
Console.WriteLine(stuff);
}
public static bool MethodWithDelegate(Func<int> delegate)
{
///do stuff
int i = delegate();
return i!=0;
}
public static void Main(String[] args)
{
var answer = MethodWithDelegate(()=> DoStuff("On This random string that the MethodWithDelegate doesn't know about."));
}
I want to store a method call in an action. That method is a static method, but with a string argument that varies. So I want to store "call StaticMethod with argument "myString" in an Action.
But... without capturing this.
I can store an anonymous method () => StaticMethod(myString) in the action , but this captures the action target (this). (Edit: it doesn't. See the accepted answer).
I can store the static method in the action, but then I'm missing the argument.
I could store the static method and the arguments separately, but due to technical reasons, this is cumbersome and ugly.
Do I have any other possibility?
[Edit]
In other words, I want to do this:
private void MyMethod(string myString){
var action = Call StaticMethod with argument myString.
}
And somewhere else, where I have access to action, but don't know anything about the string, or that there are arguments:
action.Invoke();
action can capture the string, but can't capture this (the call target of MyMethod).
Given the following assumptions:
myString is a local variable, or a parameter to the method (Not! a property or field)
StaticMethod is really a static method
There are no other delegates being constructed in the same method as you want to construct action
then the following:
public void M() {
string myString = "something";
Action action = () => StaticMethod(myString);
}
public static void StaticMethod(string value) { }
will be compiled as this:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public string myString;
internal void <M>b__0()
{
StaticMethod(myString);
}
}
public void M()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.myString = "something";
Action action = new Action(<>c__DisplayClass0_.<M>b__0);
}
As you can see, your lambda is lifted out to a generated display class, and myString is also lifted out from your method, going from a local variable to a field on that display class. This is the closure, and the object constructed in the M method will be the target of the action, and this closure will not capture this.
You can see this in action here: SharpLab
Note that small changes to your code will invalidate this as the assumptions change. For instance, if you also, in the same method, declare another delegate that also requires a closure and also requires access to this, then the same closure will be shared between the two delegates.
Example:
public void M() {
string myString = "something";
Action action = () => StaticMethod(myString);
Action otherAction = () => StaticMethod(Property);
}
public string Property => "Value";
Generates this code:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public string myString;
public C <>4__this;
internal void <M>b__0()
{
StaticMethod(myString);
}
internal void <M>b__1()
{
StaticMethod(<>4__this.Property);
}
}
public string Property
{
get
{
return "Value";
}
}
public void M()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.<>4__this = this;
<>c__DisplayClass0_.myString = "something";
Action action = new Action(<>c__DisplayClass0_.<M>b__0);
Action action2 = new Action(<>c__DisplayClass0_.<M>b__1);
}
As you can see, the same closure is used to support both delegates, and now both delegates has a reference to a closure that captures this.
If you can't define your action at call site at compile time e.:
Action a = () => StaticMethod("myString");
Then you will probably want to use expressions for this.
Example Code:
[Fact]
public void SampleActionWithoutThisScopeTests()
{
// Using Compile Time Action
Action compileTimeAction = () => MyStaticMethod("CompileTime myString");
compileTimeAction.Invoke();
// Using Compiled Expression
var myString = "Expression myString";
var methodInfo = this.GetType().GetMethod(nameof(MyStaticMethod), BindingFlags.Static | BindingFlags.Public);
var stringArgumentConstant = Expression.Constant(myString);
var callExpression = Expression.Call(null, methodInfo, stringArgumentConstant);
var lambda = Expression.Lambda<Action>(callExpression);
var action = lambda.Compile();
action.Invoke();
}
public static void MyStaticMethod(string input)
{
Console.WriteLine(input);
}
EDIT
If you can, and meet the requirements for the compiler-generated closure to not contain "this" via normal lambda syntax (see #Lasse V. Karlsen answer, then definitely use that approach!
C# 7.2 introduces the in modifier for parameters which makes perfect sense for structs and in particular for readonly structs.
It is also allowed to use it for a reference type
void Method(in StringBuilder value) { }
As reference types are passed by reference by default, is the in in the example above just a redundant modifier?
value = null is forbidden when you use in, does it mean that it spares also the copy of the reference address by just passing the original reference to the heap location and blocking changes?
in is compiled to IL in exactly the same way as ref, except in argument is marked with IsReadOnly attribute.
That means in behaves exactly as ref, but compiler (not runtime) enforces that you don't assign value to in argument.
So, as you correctly pointed out - in referenece-type argument is passed by reference (which means reference is not copied and points to original location), but compiler prevents you from changing it. I don't really see much use for it for reference types, but it won't hurt to have that, at least for consistency.
Whilst the other two answers are correct that in parameters end up as ref parameters in the resultant IL, care should be taken with the claim that this prevents the value being copied. This only holds true for readonly structs.
To demonstrate this, consider the following piece of code:
using System;
public struct S1
{
public int A;
public void ChangeA(int a) => A = a;
}
public static class Program
{
static void Main()
{
var s1 = new S1 { A = 1 };
S1Foo(in s1);
Console.WriteLine(s1.A);
}
private static void S1Foo(in S1 s) => s.ChangeA(2);
}
Since we are passing s1 by reference, one might reasonably assume that S1Foo, in calling ChangeA would then change the contents of s1. This doesn't happen though. The reason being that the s1 value is copied and a copy is passed by reference, to prevent such modifications of structs via in parameters.
If we decompile the resultant IL, you see that the code ends up as:
public static class Program
{
private static void Main()
{
S1 s = default(S1);
s.A = 1;
S1 s2 = s;
Program.S1Foo(ref s2);
Console.WriteLine(s2.A);
}
private static void S1Foo([IsReadOnly] [In] ref S1 s)
{
S1 s2 = s;
s2.ChangeA(2);
}
}
However, if we write similar code using a readonly struct, then no copying occurs. I say similar as it isn't possible to write the same code as fields and property have to be readonly in a readonly struct (the clue is in the name):
using System;
public readonly struct S2
{
private readonly int _a;
public int A => _a;
public S2(int a) => _a = a;
public void ChangeA(int a) { }
}
public static class Program
{
static void Main()
{
var s2 = new S2(1);
S2Foo(in s2);
Console.WriteLine(s2.A);
}
private static void S2Foo(in S2 s) => s.ChangeA(2);
}
Then no copy occurs in the resultant IL.
So in summary:
in is effectively a readonly ref,
The value (or reference) is passed by reference,
The compiler prevents modifying fields and properties of that reference to help enforce its readonly-ness,
To further enforce the readonly nature of the parameter, then non-readonly structs are copied before a reference to the copy is passed to the method. This doesn't occur for readonly structs.
From what I understand from official documentation, it means that arguments passed to the method will not be changed inside the method itself:
The in keyword specifies that you are passing the parameter by reference and the called method does not modify the value passed to it.
when using the in keyword with value types, it means that instead of passing the argument by value (meaning creating a new copy of the value), it is passed by reference - so it avoids the unnecessary copying.
The only useful thing I can think of for in with reference types would be generic functions with constraints.
public interface IIntContainer
{
int Value { get; }
}
public readonly struct LargeStruct : IIntContainer
{
public readonly int val0;
public readonly int val1;
// ... lots of other fields
public readonly int val20;
public int Value => val0;
}
public class SmallClass : IIntContainer
{
public int val0;
public int Value => val0;
}
public static class Program
{
static void Main()
{
DoSomethingWithValue(new LargeStruct());
DoSomethingWithValue(new SmallClass());
}
public static void DoSomethingWithValue<T>(in T container) where T : IIntContainer
{
int value = container.Value;
// Do something with value...
}
}
Hi I'm currently trying to pass methods (with no return value) as parameters to another method (so that they can be called from within the methods).
The problem I'm currently having is, that I'm using Action in the parameterlist and thus need to exactly define which parameters this method takes.
The question thus is: Is there any way to omit this? Thus that I don't have to define which parameters exactly the method has in the parameterdeclaration?
Codeexample:
public void A(int myint)
{
Console.WriteLine(myint.ToString());
}
public void B(int myint1, int myint2)
{
Console.WriteLine((myint1 + myint2).ToString());
}
public void myQuestionMethod(Action<int> parameterMethod)
{
//....Dosomething special by creating the parameters within and calling the given methods
}
myQuestionMethod(A);
myQuestionMethod(B);
Thus Aciton parameterMethod can that be replaced by something else that allows me to give methods as parameters who have differing parameters?
Edit:
I forgot to mention that the TYPE of the parameters is also not fixated.
Thus a function C could exist with (int param1, String param2)
No. There is no way to do this with the Action delegate (that's why there are 16 overloads).
You could opt, if the variables are all of the same type and have the same meaning, to create an array of integers:
public void A(params int[] myint)
{
}
public void myQuestionMethod(Action<int[]> parameterMethod)
{
//....Dosomething special by creating the parameters within and calling the given methods
}
Depending on how big your methods are, you could go for just Action and use anonymous methods rather than explicitly defining the functions
public void myQuestionMethod(Action parameterMethod)
{
//
}
...
myQuestionMethod(() => Console.WriteLine(myInt.ToString()));
myQuestionMethod(() => Console.WriteLine((myInt1 + myInt2).ToString()));
One solution would be to use reflection. Of course don't use it unless you do not have any other choice (specifying a method using its name should be avoided if possible):
public class Foo
{
public void A(int myint)
{
Console.WriteLine(myint.ToString());
}
public void B(int myint1, int myint2)
{
Console.WriteLine((myint1 + myint2).ToString());
}
public void myQuestionMethod(string parameterMethodName, params object[] parameters)
{
var method = this.GetType().GetMethod(parameterMethodName, BindingFlags.Instance | BindingFlags.Public);
method.Invoke(this, parameters);
}
}
public class Test
{
public static void Main()
{
var foo = new Foo();
foo.myQuestionMethod("B", 1, 2);
Console.Read();
}
}
In C# language and .NET framework, could you help me with understanding delegates?
I was trying to check some code, and found that the results I received were unexpected for me. Here it is:
class Program
{
public static int I = 0;
static Func<string> del = new Func<string>(I.ToString);
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del());
}
}
The answer was 0, but not 10. Why?
The reason is the following:
The way you declare the delegate it points directly to the ToString method of the static int instance. It is captured at the time of creation.
As flindeberg points out in the comments below, each delegate has a target and a method to be executed on the target.
In this case, the method to be executed is obviously the ToString method. The interesting part is the instance the method is executed on: It is the instance of I at the time of the creation, meaning that the delegate is not using I to get the instance to use but it stores the reference to the instance itself.
Later you change I to a different value, basically assigning it a new instance. This doesn't magically change the instance captured in your delegate, why should it?
To get the result you expect, you would need to change the delegate to this:
static Func<string> del = new Func<string>(() => I.ToString());
Like this, the delegate points to an anonymous method that executes ToString on the current I at the time of the execution of the delegate.
In this case, the method to be executed is an anonymous method created in the class in which the delegate is declared in. The instance is null as it is a static method.
Have a look at the code the compiler generates for the second version of the delegate:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0);
private static string cctor>b__0()
{
return UserQuery.I.ToString();
}
As you can see, it is a normal method that does something. In our case it returns the result of calling ToString on the current instance of I.
You need to pass in I to your function so that I.ToString() can be executed at the appropriate time (instead of at the time function is created).
class Program
{
public static int I = 0;
static Func<int, string> del = num => num.ToString();
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del(I));
}
}
Here is how this should be done:
using System;
namespace ConsoleApplication1
{
class Program
{
public static int I = 0;
static Func<string> del = new Func<string>(() => {
return I.ToString();
});
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del());
}
}
}
C# delegate enable encapsulate both an object and instance and a method. A delegate declaration defines a class that is derived from the class System.Delegate. A delegate instance encapsulates an invocations list, which is a list one or more method, each of which is referred to as callable entity.
learn more form
http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html
My guess is because int are passed by values not references, and for that reason when creating the delegate, it's a delegate to the method ToString of the current value of "I" (0).