Pass a method as a parameter [duplicate] - c#

This question already has answers here:
Pass Method as Parameter using C#
(13 answers)
Closed 2 years ago.
I want to be able to pass a method as a parameter.
eg..
//really dodgy code
public void PassMeAMethod(string text, Method method)
{
DoSomething(text);
// call the method
//method1();
Foo();
}
public void methodA()
{
//Do stuff
}
public void methodB()
{
//Do stuff
}
public void Test()
{
PassMeAMethod("calling methodA", methodA)
PassMeAMethod("calling methodB", methodB)
}
How can I do this?

You need to use a delegate, which is a special class that represents a method. You can either define your own delegate or use one of the built in ones, but the signature of the delegate must match the method you want to pass.
Defining your own:
public delegate int MyDelegate(Object a);
This example matches a method that returns an integer and takes an object reference as a parameter.
In your example, both methodA and methodB take no parameters have return void, so we can use the built in Action delegate class.
Here is your example modified:
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
// call the method
method();
}
public void methodA()
{
//Do stuff
}
public void methodB()
{
//Do stuff
}
public void Test()
{
//Explicit
PassMeAMethod("calling methodA", new Action(methodA));
//Implicit
PassMeAMethod("calling methodB", methodB);
}
As you can see, you can either use the delegate type explicitly or implicitly, whichever suits you.

Use Action<T>
Example:
public void CallThis(Action x)
{
x();
}
CallThis(() => { /* code */ });

Or Func<>
Func<int, string> func1 = (x) => string.Format("string = {0}", x);
PassMeAMethod("text", func1);
public void PassMeAMethod(string text, Func<int, string> func1)
{
Console.WriteLine( func1.Invoke(5) );
}

Delegates are the language feature that you're going to need to use to accomplish what you're trying to do.
Here's an example using the code you have above (using the Action delegate as a shortcut):
//really dodgy code
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
method(); // call the method using the delegate
Foo();
}
public void methodA()
{
Console.WriteLine("Hello World!");
}
public void methodB()
{
Console.WriteLine("42!");
}
public void Test()
{
PassMeAMethod("calling methodA", methodA)
PassMeAMethod("calling methodB", methodB)
}

Building on what BrunoLM did, as that example was brief.
//really dodgy code
public void PassMeAMethod(string text, Action method)
{
DoSomething(text);
method();
Foo();
}
// Elsewhere...
public static void Main(string[] args)
{
PassMeAMethod("foo", () =>
{
// Method definition here.
}
);
// Or, if you have an existing method in your class, I believe this will work
PassMeAMethod("bar", this.SomeMethodWithNoParams);
}

c# .net2.0 - Let me show a detailed answer for the topic (pass-a-method-as-a-parameter).
In my scenario i'm configuring a set of System.Timers.Timer-s, each with a different _Tick method.
delegate void MyAction();
// members
Timer tmr1, tmr2, tmr3;
int tmr1_interval = 4.2,
tmr2_interval = 3.5;
tmr3_interval = 1;
// ctor
public MyClass()
{
..
ConfigTimer(tmr1, tmr1_interval, this.Tmr_Tick);
ConfigTimer(tmr2, tmr2_interval, (sndr,ev) => { SecondTimer_Tick(sndr,ev); });
ConfigTimer(tmr3, tmr3_interval, new MyAction((sndr,ev) => { Tmr_Tick((sndr,ev); }));
..
}
private void ConfigTimer(Timer _tmr, int _interval, MyAction mymethod)
{
_tmr = new Timer() { Interval = _interval * 1000 };
// lambda to 'ElapsedEventHandler' Tick
_tmr.Elpased += (sndr, ev) => { mymethod(sndr, ev); };
_tmr.Start();
}
private void Tmr_Tick(object sender, ElapsedEventArgs e)
{
// cast the sender timer
((Timer)sender).Stop();
/* do your stuff here */
((Timer)sender).Start();
}
// Another tick method
private void SecondTimer_Tick(object sender, ElapsedEventArgs e) {..}

Related

C# : error CS0123: No overload for 'NewConnectionHandler' matches delegate 'Action<NewConnectionEventArgs>'

i have this code :
namespace Hazel
{
public struct NewConnectionEventArgs
{
public readonly MessageReader HandshakeData;
public readonly Connection Connection;
public NewConnectionEventArgs(MessageReader handshakeData, Connection connection)
{
this.HandshakeData = handshakeData;
this.Connection = connection;
}
}
}
public class UdpConnectionListener : NetworkConnectionListener
{
....
}
namespace Hazel
{
public abstract class ConnectionListener : IDisposable
{
public event Action<NewConnectionEventArgs> NewConnection;
public abstract void Start();
}
}
This i try to call it with:
static void Main(string[] args)
{
UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296));
listener.NewConnection += NewConnectionHandler;
}
private static void NewConnectionHandler(object sender, NewConnectionEventArgs args)
{
Console.WriteLine("New connection from " + args.Connection.EndPoint.ToString());
}
but i keep getting :
error CS0123: No overload for 'NewConnectionHandler' matches delegate 'Action<NewConnectionEventArgs>'
private static void NewConnectionHandler(object sender, NewConnectionEventArgs args)
should change to
private static void NewConnectionHandler(NewConnectionEventArgs args)
the event type is Action no object sender.
You have to understand what is delegate.
A delegate is a like a function pointer in C and C++, except that it can contain multiple functions. It can also return a value, in case of multiple functions the last function decides about the return value.
A delegate is a type, just like classes, structs and enums.
Example:
public delegate void Foo(int i); // Can be outside of class
public class C
{
public static void F(int i)
{
}
}
Foo foo = null;
foo += C.F; // Add C.F to foo
foo += C.F; // Add C.F to foo, second time
foo += delegate (int i) {}; // Add an anonymous function to foo
foo += (i) => {}; // Add an anonymous function to foo
foo(); // Call all functions in foo()
We can save time in case we want to create a delegate and immediately assign it a function:
MyDelegate delegate = new MyDelegate(MyFunction);
// Is the same as
MyDelegate delegate = MyFunction;
System.Action and System.Func are just handful collection of generic delegates that are predefined in .NET since .NET 2 to help us. Their definition is as follows:
public delegate void Action();
public delegate void Action<T1>(T1 t1);
public delegate void Action<T1, T2>(T1 t1, T2 t2);
// ...and so until T17
public delegate TResult Func<TResult>();
public delegate TResult Action<T1, TResult>(T1 t1);
public delegate TResult Action<T1, T2, TResult>(T1 t1, T2 t2);
// ...and so until T17
An event is just a delegate, with one important difference: you can add and remove methods from event, but you can reassign to all. Why? take the previous example:
public delegate void Foo(int i); // Can be outside of class
public class C
{
public static void F(int i)
{
}
}
Foo foo = null;
foo += C.F;
foo += C.F;
foo += delegate (int i) {};
foo = (i) => {}; // Oops, `=` instead of `+=`
foo(); // Call all functions in foo() - but they're just the last, is it overwritten the previous!
This is useful usually, but can lead to mistakes with events. Using C# events we can make that a compile error:
public delegate void Foo(int i); // Can be outside of class
public class C
{
public static event Foo E; // Cannot be outside class - events are not types, but instance of delegates
public static void F(int i)
{
}
}
C.E += C.F;
C.E += C.F;
C.E += delegate (int i) {};
C.E = (i) => {}; // Compile error!
foo(); // Call all functions in foo();
System.EventHandler and System.EventHandler<TEventArgs> are helpful delegates for events:
public delegate void EventHandler(object sender, EventArgs e);
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
This is the usual pattern for events in .NET (sending the sender and a subclass of System.EventArgs), although no-one forces that.
From the above explanation, you can understand what's wrong with your code. Your code defines an event with System.Action<T1>, then you don't have sender:
public event Action<NewConnectionEventArgs> NewConnection;
What you really want is System.EventHandler<TEventArgs>:
public event EventHandler<NewConnectionEventArgs> NewConnection;

Can a callback action take different arguments in c#?

Don't know if it's possible on c# to have a callback that takes diferent arguments.
public void Woof(){
Console.WriteLine("woof");
}
public void Woof(System.Action callback){
Console.WriteLine("woof");
callback();
}
public void Foo(System.Action callback){
callback();
callback(()=> SomeOtherFunction());
}
public void TheCaller(){
Foo(Woof());
}
I know this code won't work, but is there a way to acomplish what I want?
No, single delegate can't have varying list of arguments.
Simple solution - make your callback to accept null/nullable for arguments that you don't have:
public void Foo(Action<Action> callbackWithOptionalArg)
{
callbackWithOptionalArg(null);
callbackWithOptionalArg(() => SomeOtherFunction());
}
Foo( optionalAction => optionalAction == null ? Woof() : Wool(optionalAction));
Alternative - have an interface with multiple methods as arguments:
interface IWoof
{
void Woof();
void Woof(System.Action callback)
}
public void Foo(IWoof dog)
{
dog.Woof();
dog.Woof(() => SomeOtherFunction());
}
class MyWoof : IWoof
{
public void Woof(){
Console.WriteLine("woof");
}
public void Woof(System.Action callback){
Console.WriteLine("woof with callback");
callback();
}
}
Foo(new MyWoof());

Cannot add anything to a ThreadPool

I am trying to use ThreadPool, but it is giving me errors:
class test
{
public void testMethod1(bool param)
{
var something = !param;
}
public void testMethod2()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(testMethod1), true); //expected a 'void testMethod1(object) signature'
ThreadPool.QueueUserWorkItem(new WaitCallback(testMethod1(true))); //method name is expected
}
}
How to properly use ThreadPool?
The WaitCallback delegate expects a System.Object as it's argument. You would need to use that to pass in the value.
private void TestMethodWrapper(object param)
{
TestMethod1((bool)param);
}
public void TestMethod1(bool param)
{
var something = !param;
}
public void testMethod2()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TestMethodWrapper), true);
}
This was the common pattern early on, but the current C# language allows more flexibility. For example, using a lambda is far simpler:
public void testMethod2()
{
ThreadPool.QueueUserWorkItem(o => testMethod1(true));
}
When calling using this last method, the compiler effectively creates the wrapper method for you.
ThreadPool.QueueUserWorkItem(_ => testMethod1(true));

What is this type of delegate called(C#)

I have these lines of code.
class Program
{
public delegate void printer();
public static void Method()
{
Console.WriteLine("Hello");
}
static void Main(string[] args)
{
printer del = delegate { Method(); };
del();
Console.ReadKey();
}
}
Now what do i call this statement printer del = delegate { Method(); };.
Surely it cant be called anonymous method because here i have a named method.
It's called an Anonymous method
Surely it can't be called anonymous method because here I have a named method
It's still an anonymous method, as #Daniel pointed out in the comments what your doing is instantiating an instance of the printer delegate by assigning a method with the same signature (which happens to be...an anonymous method). You could avoid using an anonymous method completely by doing:
Printer del = Method;
It's an anonymous delegate who's only function happens to be calling a named method.
It's an anonymous method. The inside of the method does call a named one but that doesn't change the fact that the outher method is anonymous.
You can easily see this when you would expand del:
class Program
{
public delegate void printer();
public static void MethodA()
{
Console.WriteLine("Hello");
}
public static void MethodB()
{
Console.WriteLine("World");
}
static void Main(string[] args)
{
bool x = true;
printer del = delegate
{
if (x)
{
MethodA();
}
else
{
MethodB();
}
};
del();
Console.ReadKey();
}
}
If you don't want to use a delegate you could do the same with an Action:
Action delA = () => MethodA();
delA();
Action points to a void returning method that takes no parameters.
It's an anonymous method, as the others have said.
You could also accomplish the same thing with this code:
Action del = () => Method();
del();
This way, you don't need to define the delegate and use the built-in Action type.

implementing delegates in c#

This would be the first time I'd use delegates in c# so please bear with me. I've read a lot about them but never thought of how/why to use this construct until now.
I have some code that looks like this:
public class DoWork()
{
public MethodWorkA(List<long> TheList) {}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
I call MethodWorkA from a method outside the class and MethodWorkA calls MethodWork 1 and 2. When I call methodA, I'd like to pass some sort of parameter so that sometimes it just does MethodWork1 and sometimes it does both MethodWork1 and MethodWork2.
So when I call the call it looks like this:
DoWork MyClass = new DoWork();
MyClass.MethodA...
Where does the delegate syntax fit in this?
Thanks.
public void MethodWorkA(Action<ParamType1, ParamType2> method) {
method(...);
}
You can call it using method group conversion:
MethodWorkA(someInstance.Method1);
You can also create a multicast delegate that calls two methods:
MethodWorkA(someInstance.Method1 + someInstance.Method2);
For what you described, you don't need delegates.
Just do something like this:
public class DoWork
{
public void MethodWorkA(List<long> theList, bool both)
{
if (both)
{
MethodWork1(1);
MethodWork2(1);
}
else MethodWork1(1);
}
public void MethodWork1(int parameters) { }
public void MethodWork2(int parameters) { }
}
If you're just experimenting with delegates, here goes:
public partial class Form1 : Form
{
Func<string, string> doThis;
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
}
void Form1_Shown(object sender, EventArgs e)
{
doThis = do1;
Text = doThis("a");
doThis = do2;
Text = doThis("a");
}
string do1(string s)
{
MessageBox.Show(s);
return "1";
}
string do2(string s)
{
MessageBox.Show(s);
return "2";
}
}
Considering that all methods are inside the same class, and you call MethodWorkA function using an instance of the class, I honestly, don't see any reason in using Action<T> or delegate, as is I understood your question.
When I call methodA, I'd like to pass some sort of parameter so that
sometimes it just does MethodWork1 and sometimes it does both
MethodWork1 and MethodWork2.
Why do not just pass a simple parameter to MethodWorkA, like
public class DoWork()
{
public enum ExecutionSequence {CallMethod1, CallMethod2, CallBoth};
public MethodWorkA(List<long> TheList, ExecutionSequence exec)
{
if(exec == ExecutionSequence.CallMethod1)
MethodWork1(..);
else if(exec == ExecutionSequence.CallMethod2)
MethodWork2(..);
else if(exec == ExecutionSequence.Both)
{
MethodWork1(..);
MethodWork2(..);
}
}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
Much simplier and understandable for your class consumer.
If this is not what you want, please explain.
EDIT
Just to give you an idea what you can do:
Example:
public class Executor {
public void MainMethod(long parameter, IEnumerable<Action> functionsToCall) {
foreach(Action action in functionsToCall) {
action();
}
}
}
and in the code
void Main()
{
Executor exec = new Executor();
exec.MainMethod(10, new List<Action>{()=>{Console.WriteLine("Method1");},
()=>{Console.WriteLine("Method2");}
});
}
The output will be
Method1
Method2
In this way you, for example, can push into the collection only functions you want to execute. Sure, in this case, the decision logic (which functions have to be executed) is determined outside of the call.

Categories

Resources