Passing a method as a parameter with parameters - c#

So I know how to do:
void PrintFoo () { Console.Write("Foo");}
void DoSomething (Action methodToCall) { methodToCall();}
void Main () { DoSomething(PrintFoo); }
What I want to do:
void PrintFoo (string fooToPrint) { Console.Write(fooToPrint);}
void DoSomething (Action methodToCall) { methodToCall();}
void Main () { DoSomething(PrintFoo("Foo bar baz")); }
Basically call an action WITH Parameters

Use a lambda expression:
void PrintSomething(string stringToPrint) { Console.Write(stringToPrint); }
void DoSomething(Action methodToCall) { methodToCall(); }
void Main()
{
DoSomething(() => PrintSomething("Message"));
}

You may also define actions to require parameter types for the callback.
public void DoSomething(Action<string> Callback){
var result = getMyString();
Callback(result);
}
public void DoSomething(Action<string> CallBack, List<string> Parms){
var sb = new StringBuilder();
Parms.ForEach(p=> sb.Append(Parse(p));
Callback(sb.ToString());
}

Related

Generalize Invoke function and delegate

How can I factor those two function/delegate into one general function and delegate ?
Is there an easy way to do this ?
public TabControl tab;
public Label devlog;
delegate void tabHandlerCallback(bool e);
public void tabHandler(bool e)
{
if (tab.InvokeRequired)
{
tab.Invoke(new tabHandlerCallback(tabHandler), new object[] { e });
}
else
{
tab.Enabled = e;
}
}
delegate void devHandlerCallback(string e);
public void devHandler(string e)
{
if (devlog.InvokeRequired)
{
devlog.Invoke(new devHandlerCallback(devHandler), new object[] { e });
}
else
{
devlog.Text = e;
}
}
you can use following code
public delegate void InvokeDelegate();
//T_Elapsed is a thread and controls required invoke
private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.BeginInvoke(new InvokeDelegate(InvokeMethodLabel));
this.BeginInvoke(new InvokeDelegate(InvokeMethodProgressBar));
}
void InvokeMethodLabel()
{
myLabel.Text = "Test Label";
}
void InvokeMethodProgressBar()
{
progressBar.Value = (int)(progressBar.Value * 2);
}
Here is how I did it :
delegate void controlHandlerCallback(object control, object param, string field = "Text");
public void controlHandler(object control, object param, string field="Text")
{
if (((Control)control).InvokeRequired)
{
((Control)control).Invoke(new controlHandlerCallback(controlHandler), new object[] { control, param,field });
}
else
{
PropertyInfo propertyInfo = control.GetType().GetProperty(field);
propertyInfo?.SetValue(control, param);
}
}
You can make a function that can run the necessary code either directly, or by invoking.
private void InvokeIfNecessary(Control control, Action action)
{
if(control.InvokeRequired)
control.Invoke(action);
else
action();
}
// use it like this
public void devHandler(string e)
{
InvokeIfNecessary(() => devlog.Text = e);
}
public void tabHandler(bool e)
{
InvokeIfNecessary(() => tab.Enabled = e);
}

How to add method with parameter in a list

I have generic delegates.
public delegate void Metodo();
public delegate void Metodo<T>(T parametro);
public delegate void Metodo<T, U>(T parametro1, U parametro2);
public delegate void Metodo<T, U, V>(T parametro1, U parametro2, V parametro3);
public delegate void Metodo<T, U, V, W>(T parametro1, U parametro2, V parametro3, W parametro4);
And a list:
private List<Metodo> ListOfMethods;
I add methods without parameters like this:
public void Method();
ListOfMethods.Add(Method);
How i can add methods with parameters in my list ?
Like this is my whole class.
public class ListOfUpdateMethods
{
public delegate void Metodo();
public delegate void Metodo<T>(T parametro);
public delegate void Metodo<T, U>(T parametro1, U parametro2);
public delegate void Metodo<T, U, V>(T parametro1, U parametro2, V parametro3);
public delegate void Metodo<T, U, V, W>(T parametro1, U parametro2, V parametro3, W parametro4);
private List<Metodo> MetodosPreAtualizacao;
private List<Metodo> MetodosAtualizacao;
public ListOfUpdateMethods()
{
this.MetodosPreAtualizacao = new List<Metodo>();
this.MetodosAtualizacao = new List<Metodo>();
}
public void AddMetodosPreAtualizacao(Metodo m)
{
this.MetodosPreAtualizacao.Add(m);
}
public void AddMetodosAtualizacao(Metodo m)
{
this.MetodosAtualizacao.Add(m);
}
public void ExecutaMetodosPreAtualizacao()
{
foreach (var metodos in this.MetodosPreAtualizacao)
metodos();
}
public void ExecutaMetodosAtualizacao()
{
foreach (var metodos in this.MetodosAtualizacao)
metodos();
}
}
I use in Method into a Windows Form:
private void UpdadeControl(ListOfUpdateMethods list, Control control)
{
list.ExecutaMetodosPreAtualizacao();
if (control.InvokeRequired)
{
var action = new Action<ListOfUpdateMethods, Control>(UpdadeControl);
control.Invoke(action, new object[] { list, control });
}
else
{
list.ExecutaMetodosAtualizacao();
}
}
I'm looking for the best way to write a generic method to update the controls on my form.
You can create a list of MulticastDelegate. For example:
List<MulticastDelegate> multicastDelegates = new List<MulticastDelegate>();
multicastDelegates.Add(new Action(() => Console.WriteLine("Hello World!")));
multicastDelegates.Add(new Action<int>(x => Console.WriteLine(x)));
foreach (var multicastDelegate in multicastDelegates)
{
if (multicastDelegate is Action<int> actionInt)
{
actionInt(1);
}
else if (multicastDelegate is Action action)
{
action();
}
}
You could do it by creating a List<Action> and adding invocations of the various delegates.
A List<Action> could contain any sort of action, not just one of these delegates. If you encapsulate the list you can ensure that only the types of actions you want get added.
public class MetodoList
{
private readonly List<Action> _metodos = new List<Action>();
public void Add(Metodo metodo)
{
_metodos.Add(metodo.Invoke);
}
public void Add<T>(Metodo<T> metodo, T argument)
{
_metodos.Add(() => metodo.Invoke(argument));
}
public void Add<T, U>(Metodo<T, U> metodo, T thing, U uther)
{
_metodos.Add(() => metodo.Invoke(thing, uther));
}
// more of these.
public void InvokeAll()
{
_metodos.ForEach(m => m.Invoke());
}
}
While I don't know what this is for, here's how you would use it:
var metodos = new MetodoList();
var target = new HasMetodos();
metodos.Add(target.DoSomething);
metodos.Add(target.DoSomethingWithTwoArguments, "x", 1);
metodos.InvokeAll();

initialising a delegate with a string

Is there any way to initialise a delegate with a string? I.e. you won't know the name of the function that needs to be called at runtime? Or I'm guessing there is a better way of doing this?
delegate void TestDelegate(myClass obj);
void TestFunction()
{
TestDelegate td = new TestDelegate(myFuncName); // works
TestDelegate td = new TestDelegate("myFuncName"); // doesn't work
}
Update
Is is the code I currently have which is not working
class Program
{
static void Main(string[] args)
{
Bish b = new Bish();
b.MMM();
Console.Read();
}
}
class Bish
{
delegate void TestDelegate();
public void MMM()
{
TestDelegate tDel = (TestDelegate)this.GetType().GetMethod("PrintMe").CreateDelegate(typeof(TestDelegate));
tDel.Invoke();
}
void PrintMe()
{
Console.WriteLine("blah");
}
}
You can create a dynamic delegate this way
class Bish
{
delegate void TestDelegate();
delegate void TestDelegateWithParams(string parm);
public void MMM()
{
TestDelegate tDel = () => { this.GetType().GetMethod("PrintMe").Invoke(this, null); };
tDel.Invoke();
TestDelegateWithParams tDel2 = (param) => { this.GetType().GetMethod("PrintMeWithParams").Invoke(this, new object[] { param }); };
tDel2.Invoke("Test");
}
public void PrintMe()
{
Console.WriteLine("blah");
}
public void PrintMeWithParams(string param)
{
Console.WriteLine(param);
}
}

Callback syncronization between threads

I want to wait on the GetValues.Get Method and return the values syncronously to the caller. The ServerDataProvider, BookDataFetcher classes are external to mycode, on which I have no control.
Any help on how to achieve this is much appreciated.
namespace Test {
class Program
{
static void Main(string[] args)
{
GetValues val = new GetValues();
val.Get("BOOKS", DataHandler);
Console.ReadKey();
}
static void DataHandler(IList<string> values) {
}
}
class GetValues
{
public delegate void DataHandler(IList<string> values);
public event DataHandler OnReceiveDataHandler;
public void Get(string colName, DataHandler handler)
{
OnReceiveDataHandler += handler;
GetDataFromServer svr = new GetDataFromServer();
svr.OnReceiveDataHandler += OnReceiveData;
svr.GetData(colName);
}
// Callback Handler
private void OnReceiveData(IList<string> values) {
OnReceiveDataHandler(values);
}
}
class GetDataFromServer
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
internal void GetData(string columnName)
{
ServerDataProvider datafetcher = new ServerDataProvider();
datafetcher.OnReceiveDataHandler += OnReceiveData;
Task.Factory.StartNew(() => datafetcher.GetDataFromServer(columnName));
}
// Callback Handler
private void OnReceiveData(IList <string> values) {
OnReceiveDataHandler(values);
}
}
class ServerDataProvider
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
public void GetDataFromServer(string columnName)
{
BookDataFetcher b = new BookDataFetcher();
b.OnReceiveDataHandler += OnReceiveData;
Task.Factory.StartNew(() => b.GetBookData(columnName));
}
// Calback Handler
private void OnReceiveData(IList<string> values)
{
OnReceiveDataHandler(values);
}
}
class BookDataFetcher
{
internal delegate void DataHandler(IList<string> values);
internal event DataHandler OnReceiveDataHandler;
public void GetBookData(string col)
{
Thread.Sleep(5000);
OnReceiveDataHandler(new List<string> {"Book1", "Book2"});
}
}
}
What you are asking can be achieved using MethodImplAttribute
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void MethodA()

Pass a method as a parameter [duplicate]

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) {..}

Categories

Resources