Cannot use use ref or out parameter for anonymous methods - c#

static BackgroundWorker worker;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
string strClientId = "2211"; Authenticate(ref strClientId);
}
static void Authenticate(ref string strClientId)
{
Timer timer = new Timer(500);
//Error in this line
//Cannot use ref or out parameter 'strClientId' inside an anonymous method,lambda expression or query expression
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e,ref strClientId);
//timer.Elapsed += Authenticates_Timer();
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e, ref string strClientId)
{
//want to use variable here
strClientId = "";
}
if there is a way i can use ref variable while passing
parameter to event Cannot use ref or out parameter 'strClientId'
inside an anonymous method,lambda expression or query
expression.I know this is repeated question but i am unable to
figure out how to solve this have refered different posts and
posted question in codeproject too but no one is responding any
help is appreciated

I would recommend sharing strClientId as static variable:
static BackgroundWorker worker;
static string strClientId;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
strClientId = "2211";
Authenticate();
}
static void Authenticate()
{
Timer timer = new Timer(500);
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e);
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e)
{
strClientId = "";
}
Will it work for you?
Update: Ok, let's try this one:
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
string strClientId = "";
var setClientId = new Action<string>(v => { strClientId = v; });
setClientId("2211");
Authenticate(setClientId);
}
static void Authenticate(Action<string> setClientId)
{
Timer timer = new Timer(500);
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e, setClientId);
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e, Action<string> setClientId)
{
setClientId("");
}

As simple as that:
static void Authenticate(ref string strClientId)
{
Timer timer = new Timer(500);
var strClientIdVar = strClientId;
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e,ref strClientIdVar);
timer.Start();
}

Related

Passing a method to a BackgroundWorker.DoEvent C#

I am currently trying to make a regular function run as an anonymous BackgroundWorker's DoWork event. The issue I have is that the method is not running at all. The current code I have is as follows;-
public class Worker
{
BackgroundWorker worker;
public Worker(Func<bool> action)
{
worker = new BackgroundWorker();
worker.DoWork += (sender, e) => e.Result = action;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
this.action = action;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Thread completed : "+ e.Result.ToString());
}
public void DoWork()
{
Console.WriteLine("worker thread: working...");
worker.RunWorkerAsync();
//Wait for worker to complete
do { } while (worker.IsBusy);
}
}
The function is passed like this:-
Worker workerObject = new Worker(new Func<bool>(() => methodThatReturnsBool(param1, param2)));
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
How is it possible to pass the method and have it run within the background worker?
From the looks of it, you are just assigning the action itself as a result, instead of calling it.
worker.DoWork += (sender, e) => e.Result = action();
Also the waiting loop might cause problems. At least put a
do {Thread.Yield();} while (worker.IsBusy);
in there
Or use a cleaner (no busy-waiting) approach:
public class Worker
{
private BackgroundWorker _worker;
private AutoResetEvent _event;
private Func<bool> _action;
public Worker(Func<bool> action)
{
_action = action;
_event = new AutoResetEvent(false);
_worker = new BackgroundWorker();
_worker.DoWork += (sender, e) =>
{
try
{
e.Result = _action();
}
finally
{
_event.Set();
}
};
_worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Thread completed : "+ e.Result.ToString());
}
public void DoWork()
{
Console.WriteLine("worker thread: working...");
_worker.RunWorkerAsync();
_event.WaitOne();
}
}

C# Backgroundworker ConsoleWriteline

I have a simple Backgroundworker and want to write my result to the Console and I also want to report the process.
class Program
{
private static BackgroundWorker worker;
static int counter;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
counter++;
worker.ReportProgress(counter);
}
}
static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(counter);
}
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
}
But how can I give my String (or more then 1 String) to my ReportProcess Function?
You're not assigning the event handlers to the BackgroundWorker events:
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork; //here
worker.ProgressChanged += Worker_ProgressChanged; //and here
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();
Console.ReadLine();
}
Cheers
You're passing counter as the first (int percentProgress) parameter to ReportProgress, which you can access as shown in the example below using e.ProgressPercentage. You can also pass a second (object userState) parameter, which could be a string or any other object, accessed as shown in the example below using e.UserState.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker.ReportProgress(100, "Complete!");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
toolStripProgressBar.Value = e.ProgressPercentage;
toolStripStatusLabel.Text = e.UserState as String;
}
See full example at https://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripprogressbar(v=vs.110).aspx

Passing function as parameter to create delegate

I'm trying to make a helper function to make BackgroundWorkers.
Here is what I have so far.
using System.ComponentModel;
using System;
public class BackgroundThread {
BackgroundWorker worker;
public BackgroundThread(Delegate workerFunction, Delegate workerCallback) {
this.worker = new BackgroundWorker();
this.worker.DoWork += new DoWorkEventHandler(workerFunction);
this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerCallback);
}
public void Start(object argument) {
this.worker.RunWorkerAsync(argument);
}
}
Although I am getting this error.
Expression denotes a 'variable', where a 'type' or 'method group' was expected
It makes sense since normally you pass a reference to a function to the Handlers but I don't know how to do it in this context. Or is this just not possible. I don't know enough about C# delegates and such to know what to do.
Like this?
public class BackgroundThread
{
System.ComponentModel.BackgroundWorker worker;
public BackgroundThread(System.ComponentModel.DoWorkEventHandler workerFunction, System.ComponentModel.RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
public BackgroundThread(Action<object> anyWorkFunctionWithObjectArgument, Action<object> anyCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += (sender, e) => { anyWorkFunctionWithObjectArgument.Invoke(e.Argument); };
this.worker.RunWorkerCompleted += (sender, e) => { anyCallback.Invoke(e.Result); };
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
public static BackgroundThread GetDoNothingInstance()
{
return new BackgroundThread(
(sender, e) =>
{
// e is DoWorkEventArgs
},
(sender, e) =>
{
// e is RunWorkerCompletedEventArgs
});
}
public static BackgroundThread GetDoNothingInstance2()
{
Action<object> workfunction = delegate(object argument)
{
// Do nothing
};
Action<object> callback = delegate(object result)
{
// Do nothing
};
return new BackgroundThread(workfunction, callback);
}
}
Just saw your comment. This should allow you to just pass a "plain old function" without having to shape it like a handler:
class Program
{
protected static void plainOldWorkerFunction(object argument)
{
return;
}
protected static void plainOldCallbackFunction()
{
return;
}
static void Main(string[] args)
{
BackgroundThread bt = new BackgroundThread(plainOldWorkerFunction, plainOldCallbackFunction);
bt.Start(1234);
}
}
public class BackgroundThread
{
BackgroundWorker worker;
Action<object> workerAction;
Action callbackAction;
protected void doWork(object sender, DoWorkEventArgs e)
{
workerAction(e.Argument);
}
protected void callback(object sender, RunWorkerCompletedEventArgs e)
{
callbackAction();
}
public BackgroundThread(Action<object> workerFunction, Action workerCallback)
{
this.workerAction = workerFunction;
this.callbackAction = workerCallback;
this.worker = new BackgroundWorker();
this.worker.DoWork += doWork;
this.worker.RunWorkerCompleted += callback;
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
}
Original answer:
Try this constructor instead:
public BackgroundThread(DoWorkEventHandler workerFunction, RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
And just make sure your workerFunction and workerCallback have these parameters:
protected static void workerFunction (object sender, DoWorkEventArgs e)
{
return;
}
protected static void workerCallback (object sender, RunWorkerCompletedEventArgs e)
{
return;
}

c# Function work with Timer(AutoFunction)

I do have one checking function that will run once opening the application.
How to make it Auto Function like every 20 seconds run the function?
Main()
{
Checking();
}
public void Checking() // run this function every 20 seconds
{ // some code here
}
You can use the C# Timer class
public void Main()
{
var myTimer = new Timer(20000);
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Enabled = true;
Console.ReadLine();
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
Main()
{
Timer tm = new Timer();
tm.Interval = 20000;//Milliseconds
tm.Tick += new EventHandler(tm_Tick);
tm.Start();
}
void tm_Tick(object sender, EventArgs e)
{
Checking();
}
public void Checking()
{
// Your code
}

How do I pass an object into a timer event?

Ok so I am using System.Timers.Timer in .Net 4 with C#.
I have my timer object like so:
var timer = new Timer {Interval = 123};
I have my Timer Elapsed event handler pointed at a method like so:
timer.Elapsed += MyElapsedMethod;
And my method looks like this:
static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Foo Bar");
}
I want to pass a string into this method, how do I do this?
Thanks
The easiest way to do this is to change the event handler into an anonymous function. It allows you to pass the string at the point of declaration.
string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);
static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
...
}
If you want to be able to unregister your "Elapsed" event handler again, you shouldn't use a delegate without remembering it in a variable.
So another solution could be to create a custom class based on Timer. Just add whatever members you like and get your custom Timer object back from the "sender" argument of the "Elapsed" event handler:
class CustomTimer : System.Timers.Timer
{
public string Data;
}
private void StartTimer()
{
var timer = new CustomTimer
{
Interval = 3000,
Data = "Foo Bar"
};
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string data = ((CustomTimer)sender).Data;
}
This strategy of course works for other events and classes too, as long as the base class is not sealed.
You can save string in some object and read it in event handler:
static string _value;
static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
Console.WriteLine(_value);
}
UPDATE: same code via different syntax:
timer.Elapsed += (s,e) => Console.WriteLine(_value);
UPDATE: Consider also using System.Threading.Timer instead
State state = new State();
Timer timer = new Timer(OnTimer, state, 0, 123);
state.Value = "FooBar"; // change state object
You can retrieve state in timer callback:
static void OnTimer(object obj)
{
State state = obj as State;
if (state == null)
return;
Console.WriteLine(state.Value);
}
Timer aTimer = new Timer(300);
aTimer.Elapsed += delegate { PublishGPSData(channel, locationViewModel); };
// Hook up the Elapsed event for the timer.
aTimer.AutoReset = true;
aTimer.Enabled = true;
private void PublishGPSData(IModel channel, LocationViewModel locationViewModel)
{
};
Use a field in the same class to hold whatever string you want and then retrieve it in you elapsed event handler. You'll have to be careful about cross-threading issues however.
I wrote this simple class to handle this:
using System;
using System.Timers;
namespace MyProject.Helpers
{
public class MyTimer
{
private volatile Timer _timer = new Timer();
private volatile bool _requestStop = false;
private MyElapsedEventHandler _eventHander;
private MyElapsedEventHandlerWithParam _eventHandlerWithParam;
private object _param;
public MyTimer(int interval, MyElapsedEventHandler elapsedEventHandler, bool autoReset = false)
{
_timer.Interval = interval;
_timer.Elapsed += ElapsedWrapper;
_timer.AutoReset = autoReset;
_eventHander = elapsedEventHandler;
Start();
}
public MyTimer(int interval, MyElapsedEventHandlerWithParam elapsedEventHandler, object param, bool autoReset = false)
{
_timer.Interval = interval;
_timer.Elapsed += ElapsedWrapperWithParam;
_timer.AutoReset = autoReset;
_eventHandlerWithParam = elapsedEventHandler;
_param = param;
Start();
}
private void ElapsedWrapper(object sender, ElapsedEventArgs e)
{
if (!_requestStop && _eventHander != null)
{
_eventHander();
}
}
private void ElapsedWrapperWithParam(object sender, ElapsedEventArgs e)
{
if (!_requestStop && _eventHandlerWithParam != null)
{
_eventHandlerWithParam(_param);
}
}
public void Stop()
{
_requestStop = true;
_timer.Stop();
}
public void Start()
{
_requestStop = false;
_timer.Start();
}
}
public delegate void MyElapsedEventHandlerWithParam(object param);
public delegate void MyElapsedEventHandler();
}
use it like this:
void Main(string[] args){
new MyTimer(durationInSeconds * 1000, EventHandler, "some string");
}
void EventHandler(object param){
doSomethingWithString((string)param);
}
you can also pass the event arguments or any kind of parameters if you edit the delegate (and the call of the event handler in MyTimer class).
Why not just use a Timer and an ElapsedEventHandler?
namespace TimerEventHandler
{
class Program
{
private static Timer myEventTimer;
static void Main(string[] args)
{
// 5 second timer multiply 1000 milliseconds by the time
//e.g. new Timer(60 * 1000 * 10) = 10 minutes
myEventTimer = new Timer(5 * 1000 * 1);
myEventTimer.Enabled = true;
myEventTimer.Elapsed += new ElapsedEventHandler(TimerSchedule_Elapsed);
Console.WriteLine("Timer started!");
// make a thread and wait forever just so console does not go away
Thread.Sleep(Timeout.Infinite);
}
private static void TimerSchedule_Elapsed(object sender, ElapsedEventArgs e)
{
// do something
Console.WriteLine("Timer elapsed!");
}
}
}

Categories