I was just experimenting and ended up with the following snippet:
public static class Flow {
public static void Sequence(params Action[] steps) {
foreach (var step in steps)
step();
}
}
void Main() {
Flow.Sequence(() => F1(), () => F2());
Flow.Sequence(F1, F2); // <-- what makes this equiv to the line above?
}
void F1() { }
void F2() { }
I didn't realize that a method name alone was the same as an Action.
What is making this so?
In C#, delegates are nothing more than method pointers. They can point to existing methods in a class, or independent anonymous delegate objects altogether.
This paragraph from the above link should explain what's happening in your code:
Any method that matches the delegate's signature, which consists of the return type and parameters, can be assigned to the delegate. This makes is possible to programmatically change method calls, and also plug new code into existing classes. As long as you know the delegate's signature, you can assign your own delegated method.
That is, when resolving delegate types, what's considered are their signatures, rather than their names.
In your case, your F1() and F2() methods, taking no parameters and returning nothing, have matching signatures with the parameterless Action delegate:
public delegate void Action();
Therefore, they're implicitly convertible to Action.
If you try to pass a method with a different return type or at least one parameter, you'll get a compile-time error as it won't correspond to Action's signature.
Basically, this is kind of what is happening in the background:
void Main()
{
Flow.Sequence(new Action(delegate(){ F1(); }), new Action(delegate(){ F2(); }));
Flow.Sequence(new Action(F1), new Action(F2));
}
They're not EXACTLY equivalent, but they're very close. They would render the same results at run-time, the only difference being that the arguments in the first Sequence invocation would be an Action which invokes an anonymous method which then invokes the static methods F1 and F2; the second Sequence invocation would be an Action which invokes the static methods F1 and F2.
I hope this helps.
The compiler uses an implicit conversion from a method group to a delegate of compatible type (in this case a void returning method taking no arguments), the method names here are irrelevent.
Related
class Program{
static void Main(){
test11 jhbee = Program.test; //error
test11 yep = delegate { }; //no error
}
static void test() { }
}
delegate void test11(int r);
So I have the delegate test11 which returns void and takes 1 parameter.
whn I try to assign a parameterless method to an instance of test11, the compiler, obviously issues an error but when I assign a parameterless anonymous method to an instance of test11, no error is issued.
I mean, I can see that there is no obstacle for it to work but can you please tell me why is this so? Is there a good reason for this?
From the documentation:
When you use the delegate operator, you might omit the parameter list. If you do that, the created anonymous method can be converted to a delegate type with any list of parameters
So while it appears that way, the created anonymous method is not really parameterless - its parameter list has just not been defined.
As for the reason why this is an option, this answer to a related question might help explain it.
Is there a way to pass different methods as parameter into another method in C#? I have some code like this below
class Program
{
void Action1(string s){...}
string Func1(string s){...}
void RegisterAction(Action<string> action){...}
void RegisterFunc(Func<string, string> func){...}
void Register(????){ }
void Run()
{
RegisterAction(Action1); // ok
RegisterFunc(Func1); // ok
Register(Action1); // ?
Register(Func1); //?
}
}
I want to pass Action1 and Func1 into the same method 'Register', in which I can use reflection to implement my logic. but the Action<string>, Func<string,string>are different delegates, perhaps I will have to deal with Action<int>, Func<object> and many other types I don't want to write the 'register' methods for every action and function.
Any help? Thank you.
There is a base type - MulticastDelegate which itself has a base type of Delegate - but the problem is that you're relying on a method group conversion to a delegate type, and that requires a specific delegate type to convert to. Register(Action1) could convert the method group Action1 to any delegate type returning void and accepting a string - there can be multiple such delegates. How would the compiler know which one you mean?
What you could do is keep your RegisterAction and RegisterFunc methods, but then use a common implementation which stores the delegates in (say) a List<Delegate>.
My understanding of Actions in C# is that they are just a specific version of a delegate, namely one with no parameters and no return type.
If I create a class like this...
class TrainSignal
{
public delegate void TrainsAComing();
public void HerComesATrain()
{
TrainsAComing();
}
}
...it won't compile since I haven't created an instance of the delegate. However if I replace the delegate definition with that of an Action like below it compiles:
class TrainSignal
{
public Action TrainsAComing;
public void HerComesATrain()
{
TrainsAComing();
}
}
I thought perhaps that maybe an Action is static or something like that (thereby allowing us to call it by it's name without instantiating it) but that doesn't seem to be the case.
Can anyone explain why the second code block is legal?
This line
public delegate void TrainsAComing();
defines a public delegate type called TrainsAComing, nested inside your class. This would let users create delegates of type TrainSignal.TrainsAComing, but TrainSignal would have no member to store an instance of such delegate.
In other words, declaration of the delegate does not define a member of delegate type. You need another declaration for that:
class TrainSignal
{
public delegate void TrainsAComing(); // The delegate type
public TrainsAComing OnTrainsAComing; // The member of delegate type
public void HerComesATrain()
{
OnTrainsAComing();
}
}
Action, on the other hand, is already a type, similar to delegate TrainsAComing from your example. Hence, the definition
public Action TrainsAComing;
makes TrainsAComing a member of TrainSignal capable of storing a delegate.
An Action field is a field like any other. It's a ref type, so the field is null initialized. You will receive a NullReferenceException. This is perfectly safe but not useful.
Maybe you meant to actually reference a function?
Action TrainsAComing = () => Console.WriteLine("...");
Or maybe, the confusion comes from the fact that the first code snippet declares a delegate type and the second one declares a field of a delegate type.
Going back to basics - a little confused on the syntax sugar for delegates. Here is my scenario:
I have a delegate which takes zero paramaters and returns void. Essentially an Action delegate with zero parameters. Code snippet below (purposefully using basic delegate syntax versus Action Delegate usage)
class Program
{
public delegate void Del(); // Declare
static void Main(string[] args)
{
Del d = MethodCalled; //Instantiate
d(); //Invoke
Console.ReadLine();
}
public static void MethodCalled()
{
Console.WriteLine("Hello");
}
}
Question: How can I combine instantiate and invocation calls in one sentence (for delegates with no return) similar to below (use-case where I have a return value coming from a Delegate:
//Instantiate & Invoke Delegate
string handler = MethodCalled("Hello");
Please note - this question is not how to write a Action Delegate equivalent using Anonymous Method or Lamda Expressions. That I know. Even in there I still have to do invocation of the delegate d().
My question is more related to how do i combine 2 statements (irrespective of the syntax used - basic delegate, Action delegate)
new SomeDelegate(SomeMethod)(SomeParameter);
consider following:
1st APPROACH:
public void f3()
{
f2();
f1();
}
and this ...
2nd APPROACH:
class Sample
{
public delegate void MyDelegate(string s);
MyDelegate obj;
public Sample()
{
obj += new MyDelegate(input);
obj+=new MyDelegate(something);
obj += new MyDelegate(someStaticMethod);
}
}
When i call f3() it will call the functions listed inside it ... same would happen when i will invoke a delegate ... so whats the use of delegate to handle some event when i can use 1st approach ... the 1st approach too encapsulates the method call..
In case of the delegate, the invocation order of the attached functions is not specified.
Also, you can attach any number of functions to it, even during runtime, from other objects, not just the hard coded ones as in the first approach. The delegate has wider usage.
First approach is static. Delegate approach allows you or a caller to determine what gets called at a later time.