I'm using this to change something on other thread:
MethodInvoker m = () => { login_submit.Text = "Login"; };
if (InvokeRequired)
{
BeginInvoke(m);
}
else
{
Invoke(m);
}
this is working fine.
How can I pass argumets to that lamba expression?
I want to do sth like that:
MethodInvoker m = (string txt) => { login_submit.Text = txt; };
if (InvokeRequired)
{
BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
Invoke(m); // I need to pass txt string in some way here.
}
If this is a common scenario for you, I suggest writing an extension method:
public static class ControlExtensions
{
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired) control.BeginInvoke(action);
else action();
}
}
class MyControl : UserControl
{
void M(string s)
{
// the lambda will capture the string in a closure
// the compiler does all the hard work for you
this.EnsureInvokeAsync(() => _button.Text = s);
}
}
Also, you should look into using BackgroundWorker or tasks for async operations.
If InvokeRequired is false then you don't need to worry about invoking anything at all - you're already on the right thread.
A better solution might be something like this:
public delegate void InvokerDelegate(string data);
public void DoStuff(string data){
login_submit.Text = data;
}
and then when calling it do:
if (InvokeRequired){
Invoke(InvokerDelegate(DoStuff), "something");
}
else{
DoStuff("Something");
}
A fairly common pattern you will see is to do something like this for functions that manipulate the GUI in a multithreaded environment
public delegate void InvokerDelegate();
public void DoGuiStuff(){
if (login_submit.InvokeRequired){
login_submit.Invoke(InvokerDelegate(DoGuiStuff));
return;
}
login_submit.Text = "Some value";
}
If you use the above pattern the function checks to see if an invoke is required and if so Invokes itself on the right thread. It then returns. When it invokes itself the check to see if an invoke is required returns false so it doesn't bother invoking itself again - it just runs the code.
Edit: I just went back to winforms and tried to use that pattern only to spend a couple of frustrating minutes trying to work out why I couldn't invoke a lambda. I thought I'd better come back and update this answer to add the required casting in case anyone else tried to use it.
MethodInvoker is a delegate type that doesn't have any parameters. If I understand you correctly, you can do it like this:
string txt = "some text";
MethodInvoker m = () => { login_submit.Text = txt; };
You can use closures to pass the value into the lambda's body.
string value = "Login";
MethodInvoker m = () => { login_submit.Text = value; };
if (InvokeRequired)
{
BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
Invoke(m); // I need to pass txt string in some way here.
}
or you can use class member's data
Related
I have a very ugly piece of code that is scattered throughout a project. The only difference in this piece of code is one line where a different method is called. The method that's called always returns a bool.
I want to refactor this and extract it into its own method and pass the 1 liner into this method (if possible) from my understanding I can use a Func<> to do this.
Here is what I am trying to do. I have tried to keep things as clear as possible
public async Task<bool> SomeMethod()
{
//code removed for readability.
//IsCustomerComplete will return a bool
var process = await RepeatableMasterPiece(1, 2, _myRepo.IsCustomerComplete(someParameterRequired));
//do something with process result
return process;
}
private async Task<bool> RepeatableMasterPiece(int param1, int param2, Func<Task<bool>> method)
{
int retry = 0;
bool soapComplete = false;
string soapFault = "just a placeholder for example";
bool blackListStatus = false;
while (!soapComplete && retry <= 1)
{
try
{
if (soapFault != null)
{
//do some stuff with param1 & param2 here
}
if (!soapComplete)
{
return await method.Invoke();
}
}
catch (FaultException ex)
{
soapFault = ex.Message;
retry++;
if (retry > 1)
{
throw ex;
}
}
}
}
From the repo
public async Task<bool> IsCustomerComplete(int id)
{
...removed other code here
return true;
}
Does this make sense, am I on the right track, from the examples I have found they only show Funcs<> passing in a string or int which makes things look a whole lot simpler.
If I understand your goal, you're very close. The biggest thing you're missing is the conversion of your method to a Func<> delegate. In your question, you included the argument parentheses. You don't need these if you're not invoking the method.
So, basically, this is what you probably want.
var process = await RepeatableMasterPiece(1, 2, _myRepo.IsCustomerComplete);
Here is an example based on your provided details.
public async Task SomeMethod() {
//code in method.
var _myRepo = new repo();
var someParameterRequired = 1;
var process = await RepeatableMasterPiece(1, 2, () => _myRepo.IsCustomerComplete(someParameterRequired));
//do something with process result
}
private async Task<bool> RepeatableMasterPiece(int param1, int param2, Func<Task<bool>> method) {
int retry = 0;
bool soapComplete = false;
string soapFault = "just a placeholder for example";
bool blackListStatus = false;
while (!soapComplete && retry <= 1) {
try {
if (soapFault != null) {
//do some stuff with param1 & param2 here
}
if (!soapComplete && method != null) {
return await method();
}
} catch (FaultException ex) {
soapFault = ex.Message;
retry++;
if (retry > 1) {
throw ex;
}
}
}
return false;
}
The assumption here is that all the target methods will be returning Task<bool>
If the target function does not require any parameters then you can do as mentioned in other answer and just provide the function itself without the parenthesis.
I would checkout Action<T> and Func<T, TResult> delegates.
Use an Action<T> delegate when you wish to pass in an void anonymous method.
Use an Func<TResult> delegate when you need to pass in a anonymous method with a return type.
MSDN has some good examples:
Func Delegates MSDN
Action Delegates MSDN
I have used actions and function many times over my career. They come in handy when adding features to tightly coupled code that cannot be refactored.
However, their correct usage should be used when writing loosely coupled code. There are many times where I wanted to give the implementer the option to provide their own functionality.
How can I write an extension method for an existing method like :
static class Extensions
{
public static void RunAsThread(this Action func)
{
Thread t = new Thread(delegate()
{
try
{
if (func != null)
func();
}
catch (ThreadInterruptedException tie) { }
catch (ThreadAbortException tae) { }
catch (Exception ex)
{
Logger.LogDebug(ex);
}
});
t.Start();
}
}
is there any way that i can run this methods perfectly in the way i wanted
class WorkingClass
{
public void Work()
{
//Works fine
((Action)DoSomething).RunAsThread();
//Works fine
Extensions.RunAsThread(DoSomething);
//But I really need this to work
DoSomething.RunAsThread();
}
private void DoSomething()
{
//Do Something
}
}
I really wanted to make DoSomething.RunAsThread() work.
I tried to change "static void RunAsThread(this delegate .... or this Delegate)".
Could not do it properly.
Is there any work around for that? Is there any way for that?
No, you can't do this, as DoSomething is not a type, it's a method.
Also, just because you can attach an extension method to a type it doesn't mean you should..!
If DoSomething doesn't have to be an actual method, a slight tweak would make this compile:
class WorkingClass
{
public void Work()
{
//Works fine
((Action)DoSomething).RunAsThread();
//Works fine
Extensions.RunAsThread(DoSomething);
//But I really need this to work
DoSomething.RunAsThread();
}
private Action DoSomething = () =>
{
//Do Something
};
}
Whether that fits in with everything else you're writing or not, I couldn't say.
DoSomething is just a "Method group" it will be implicitly converted to Action or compatible delegate type whenever possible.
DoSomething itself not a Delegate, so not possible. but you could do the following with the help of implicit method group conversion.
Action a = DoSomething;
a.RunAsThread();
I've used delegates in the past so I'm familiar with their use and benefits. I've also done a lot of reading/research, but I'm trying to wrap my head around this and getting nowhere. I'd like to use a delegate (I believe) to encapsulate some code or use a delegate within a method to call some outside code.
I'm using the same code in 20 different places to wrap an entity framework update in a transaction. I would like the code in one place; however, I can't do it in a method by itself because there is a middle part that will change each time. I'm looking for some ideas / clarification on how I can best do this (.net 3.5, ms sql 2010). - thnx
code sample:
void AddItem(string objDetails)
{
// setup method specific entity objects
SomeObject obj = new SomeObject { Details = objDetails };
//////// Begin transaction code that I would like to encapsulate ///////
bool success = false;
using (Entities data = new Entities())
{
for (int i = 0; i < s.BaseSettings.CommandRetries; i++)
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
//////////////////////////////////////////////////////////////
///////// BEGIN Code that I would like to change / call different each time ////////
data.AddToSOMEOBJECTs(obj);
//////////////// END //////////////////////////////////
//// RETURN TO ENCAPSULATED CODE ////
data.SaveChanges(false);
transaction.Complete();
success = true;
break;
}
catch (Exception ex)
{
if (ex.GetType() != typeof(UpdateException))
{
throw new Exception("Unhandled db exception.");
}
}
}
}
if (success)
{
data.AcceptAllChanges();
}
else
{
throw new Exception();
}
}
}
You pass the function a delegate (or lambda) that does the custom bit
like this
void AddItem<T>(string objDetails, Func<T> custom) {
.
. common
.
.
T someReturn = custom();
.
. common
.
}
add call like this perhaps:
Func<int> custom = () => {
// do something custom
return 9;
}
// Call common function
AddItem<int>(..., custom);
All that matters is that the interface for the Func matches what you need.
You can pass different methods by using a delegate and an event. Here's an example of a class that does this:
class SampleClass
{
public delegate void TransactionDelegate();
public event TransactionDelegate MyTransactionDelegate;
public void DoSomething()
{
MyTransactionDelegate();
}
}
You can then use a lambda expression to pass methods to the event like this:
class MainClass
{
public static void Main (string[] args)
{
var test = new SampleClass();
test.MyTransactionDelegate += () => {Console.WriteLine("Success");};
test.DoSomething();
}
}
You can do anonymous functions in C# like you can in JavaScript:
JavaScript:
var s = (function ()
{
return "Hello World!";
}());
C#:
var s = new Func<String>(() =>
{
return "Hello World!";
})();
... In JavaScript you can pass functions to be executed by other functions. On top of that; you can pass parameters to the function which gets executed:
var f = function (message) // function to be executed
{
alert(message);
};
function execute(f) // function executing another function
{
f("Hello World!"); // executing f; passing parameter ("message")
}
Is the above example possible in C#?
Update
Use-case: I am iterating over a bunch of database, logging specific entities. Instead of calling my second function (F()) inside Log() of Logger, I'd like to call F() outside the class.
... Something along the lines of:
public void F(String databaseName)
{
}
public class Logger
{
public void Log(Function f)
{
var databaseName = "";
f(databaseName);
}
}
Absolutely - you just need to give the method an appropriate signature:
public void Execute(Action<string> action)
{
action("Hello world");
}
...
Execute(x => Console.WriteLine(x));
Note that you do have to specify the particular delegate type in the parameter - you can't just declare it as Delegate for example.
EDIT: Your database example is exactly the same as this - you want to pass in a string and not get any output, which is exactly what Action<string> does. Except if you're trying to call an existing method (F() in your code) you don't even need a lambda expression - you can use method group conversions instead:
public void F(String databaseName)
{
}
public class Logger
{
public void Log(Action<string> f)
{
var databaseName = "";
f(databaseName);
}
}
// Call it like this:
Logger logger = new Logger(...);
logger.Log(F);
You can pass delegate:
var f = (Action<string>)
(x =>
{
Console.WriteLine(x);
}
);
var execute = (Action<Action<string>>)
(cmd =>
{
cmd("Hello");
}
);
execute(f);
according your Update part:
you need a container to keep your functions
IList<Action<string>> actionList = new List<Action<Sstring>>();
in your Log() function you can add your F() to the container:
actionList.Add(F);
then invoke the function(s) somewhere outside:
foreach (Action<string> func in actionList)
{
func("databasename");
}
Like:
var s = new Func<String, string>((string name) =>
{
return string.Format("Hello {0}!", name);
});
?
Why can't you pass an anonymous method as a parameter to the BeginInvoke method? I have the following code:
private delegate void CfgMnMnuDlg(DIServer svr);
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke((CfgMnMnuDlg)ConfigureMainMenu,
new object[] { server});
}
else
{
// Do actual work here
}
}
I'm trying to avoid declaring the delegate. Why can't I write something like the below instead? Or can I, and I just can't figure out the correct syntax? The below currently generates an:
Argument type 'Anonymous method' is not assignable to parameter type 'System.Delegate'
Ok, that's right of course, but is there some other syntax I can use to do this (avoid having to declare a separate delegate in order to use BeginInvoke()?
(Being able to do this would fit in neatly with the concept of using anon methods/lamdas in place of explicit delegates which works so cleanly everywhere else.)
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke( // pass anonymous method instead ?
delegate(DIServer svr) { ConfigureMainMenu(server);},
new object[] { server});
}
else
{
// Do actual work here
}
}
Try this:
control.BeginInvoke((MethodInvoker) delegate { /* method details */ });
Or:
private void ConfigureMainMenu(DIServer server)
{
if (control.InvokeRequired)
{
control.BeginInvoke(new Action<DIServer >(ConfigureMainMenu), server);
}
else
{
/* do work */
}
}
Or:
private void ConfigureMainMenu(DIServer server)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
// Private variable
_methodInvoker = new MethodInvoker((Action)(() => ConfigureMainMenu(server)));
_methodInvoker.BeginInvoke(new AsyncCallback(ProcessEnded), null); // Call _methodInvoker.EndInvoke in ProcessEnded
}
else
{
/* do work */
}
}
You should be able to write something like this:
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke(new Action<DIServer>(ConfigureMainMenu),
new object[] { server});
}
else
{
// Do actual work here
}
}
You could write an extension method that would wrap anonymous methods, and even take care of the InvokeRequired semantics:
public static void InvokeAction(this Control ctl, Action a)
{
if (!ctl.InvokeRequired)
{
a();
}
else
{
ctl.BeginInvoke(new MethodInvoker(a));
}
}
This would allow you to do:
control.InvokeAction(delegate() { ConfigureMainMenu(server); });
You can do this in a single method by calling invoking yourself:
ClassData updData = new ClassData();
this.BeginInvoke(new Action<ClassData>(FillCurve),
new object[] { updData });
...
public void FillCurve(ClassData updData)
{
...
}
For completely anonymous methods with a limited number of parameters:
Func<int, int?> caller = new Func<int, int?>((int param1) =>
{
return null;
});
caller.BeginInvoke(7, new AsyncCallback((IAsyncResult ar) =>
{
AsyncResult result = (AsyncResult)ar;
Func<int, int?> action = (Func<int, int?>)result.AsyncDelegate;
action.EndInvoke(ar);
}), null);
You can use one of the other Func delegate types as needed.
I've tried a bunch of different methods but none work. ie...
// Fails -- cannot convert lamda to System.Delegate
mnMnu.BeginInvoke( (DIServer svr)=> {ConfigureMainMenu(server);}, new object[] server);
// Fails -- cannot convert anonymous method to System.Delegate
mnMnu.BeginInvoke( new delegate(DIServer svr){ConfigureMainMenu(server);}, new object[] server);
So, the short answer is no. You could create short helper delegates in the given context and use lambdas to make it a bit neater but that's pretty much it.
EDIT: Turns out I'm wrong. The methodinvoker answer below works.
See this page