I am trying to make a new Timers class to aid with my learning of c#. How would I let an argument for a function be a function?
It's pretty simple. Just make the argument be some kind of delegate type, like Action or Func.
void PassAnAction(Action action)
{
action(); // call the action
}
T PassAFunction<T>(Func<T> function)
{
return function();
}
public class MyTimer {
private readonly Action _fireOnInterval;
public MyTimer(Action fireOnInterval, TimeSpan interval, ...) {
if (fireOnInterval == null) {
throw new ArgumentNullException("fireOnInterval");
}
_fireOnInterval = fireOnInterval;
}
private void Fire() {
_fireOnInterval();
}
...
}
You can call it like this:
new MyTimer(() => MessageBox.Show("Elapsed"), TimeSpan.FromMinutes(5), ...)
Related
I want to be able to perform workloads at intervals.
I want to be able to make this class generic so I can pass it whatever "workload" I want and my timer function just does it. I also would like a means of "returning" the workload response back to the caller.
As an example. Let's say I have a series of classes I have built that download data from a JSON API, or scrape a web page. This web scraper/API downloader needs to download pages from a site at different intervals. Each page will take a different number of parameters. I have found something online that indicates setting the Elapsed event to a delegate. This "may"work but I need to have the passed in delegate "dynamic" itself. So the Start method below which accepts a Func won't be correct from a "generic" standpoint, which is what I am after.
The solution itself is just an example of a line of thinking. Am open to other generic alternatives that help me achieve this.
public abstract class TimerWorkerDelegate : IDisposable, ITimerWorker
{
protected System.Timers.Timer DataTimer;
public virtual void Start(Func<string> callback,double interval)
{
DataTimer = new System.Timers.Timer();
DataTimer.Interval = interval;
DataTimer.Elapsed += delegate {
callback();
};
if (!DataTimer.Enabled)
DataTimer.Enabled = true;
//IDisposable code
}
}
I might not understand 100% what you are REALLY trying to achieve, but... maybe something like.
public class Worker<T>
{
public event EventHandler<T> OnCompleted;
public Worker()
{}
public Worker(Func<T> fn, int interval)
{
Func = fn;
Interval = interval;
}
public async void Start()
{
if (Func == null)
throw new ArgumentNullException();
while (true)
{
await Task.Delay(Interval);
try
{
var result = Func();
OnCompleted(this, result);
}
catch
{
return; // handle
}
}
}
public Func<T> Func { get; set; }
public int Interval { get; set; }
}
And then usage in Console tester app as
public static void Main(string[] args)
{
var worker = new Worker<string>
{
Interval = 1000,
Func = () => { return string.Format("did some work at {0}", DateTime.Now); }
};
worker.OnCompleted += (sender, result) => { Console.WriteLine(result); };
worker.Start();
Console.ReadLine();
}
If you're open to using a library you could look at System.Reactive
With it you could setup something very easily to accomplish what you are looking to do.
Below is a very rudimentary implementation of something that could work for you:
void Main()
{
var scheduled = Schedule(
TimeSpan.FromSeconds(1),
() => Console.WriteLine($"The current time is: {DateTime.Now}"));
Console.ReadLine();
// Dispose will stop the scheduled action
scheduled.Dispose();
}
public IDisposable Schedule<T>(TimeSpan interval, Func<T> func)
=> Observable.Interval(interval).Subscribe(_ => func());
public IDisposable Schedule(TimeSpan interval, Action action)
=> Observable.Interval(interval).Subscribe(_ => action());
today i was looking for some projects with ilspy i did not understand how Actions can be used like this, in one class this method is called
public void Login(Action success, Action<bool> failure)
{
if (!FB.IsInitialized)
{
Debug.Log("[FB] Not yet initialized. Will init again!");
FB.Init(new InitDelegate(this.OnInitComplete), null, null);
return;
}
new LoginWithReadPermissions(this.READ_PERMISSIONS, delegate
{
ServiceLocator.GetDB().SetBool("facebookBound", true, false);
this.OnLoginCompleted(success, failure);
}, delegate
{
failure(false);
});
}
and this is the other class that is called by above method
public class LoginWithReadPermissions
{
private readonly Action _failureCallback;
private readonly Action _successCallback;
public LoginWithReadPermissions(string[] scope, Action success, Action failure)
{
this._successCallback = success;
this._failureCallback = failure;
FB.LogInWithReadPermissions(scope, new FacebookDelegate<ILoginResult>(this.AuthCallback));
}
private void AuthCallback(ILoginResult result)
{
if (result.Error == null && FB.IsLoggedIn)
{
this._successCallback();
}
else
{
this._failureCallback();
}
}
}
Can someone please explain what is going on there I have never faced with this kind of Action usage. Thanks for replies.
public void Login(Action success, Action<bool> failure)
{
if (!FB.IsInitialized)
{
Debug.Log("[FB] Not yet initialized. Will init again!");
FB.Init(new InitDelegate(this.OnInitComplete), null, null);
return;
}
new LoginWithReadPermissions(this.READ_PERMISSIONS, delegate
{
ServiceLocator.GetDB().SetBool("facebookBound", true, false);
this.OnLoginCompleted(success, failure);
}, delegate
{
failure(false);
});
}
The code above is just shorthand for this:
public void Login(Action success, Action<bool> failure)
{
Action successAction = () =>
{
ServiceLocator.GetDB().SetBool("facebookBound", true, false);
this.OnLoginCompleted(success, failure);
};
Action failureAction = () =>
{
failure(false);
};
if (!FB.IsInitialized)
{
Debug.Log("[FB] Not yet initialized. Will init again!");
FB.Init(new InitDelegate(this.OnInitComplete), null, null);
return;
}
new LoginWithReadPermissions(this.READ_PERMISSIONS, successAction, failureAction);
}
Basically what I'm doing is I'm creating a temporary buffer that writes data to a byte[] and then returns the size of the buffer; I'm then using this to attempt to de-segmentate my code over a network. (Trying to get my C# Client to work properly with Netty's FrameDecoder class)
Basically, I'm storing all of my Actions in a List to be called over the network once I find the buffer-size(Dynamic)
public void SendBuffer(DataOutputStream ClientOuput)
{
ClientOuput.WriteInt(GetBufferSize());
foreach (Action a in executionList)
{
// What Do?
}
}
My problem is I need to Invoke the method inside of the DataOutputStream that's passed through the SendBuffer parameters, so something like
ClientOutput.a.invoke();
What's the best way to do this?
It's not that clear what you are asking but I try to answer anyway. So you have bunch of actions (defined somewhere) that you want to be executed by instance of DataOutputStream? Then you could do something like:
public async void SendBuffer(DataOutputStream clientOuput)
{
var executionList = new List<Action>()
{
() => { Debug.WriteLine("whatyousay"); Thread.Sleep(1500); },
() => { Debug.WriteLine("allyourbase"); Thread.Sleep(1500); },
};
clientOuput.WriteInt(1);
foreach (Action action in executionList)
await clientOuput.Execute(action);
Debug.WriteLine("arebelongtous");
}
Here DataOutputStream is just
public class DataOutputStream
{
// await and actions will be executed in given order, non-blocking
public Task Execute(Action action)
{
return Task.Run(action);
}
// fire & forget, non-blocking
public void BeginInvoke(Action action)
{
action.BeginInvoke(callback => {}, null);
}
// blocking
public void Invoke(Action action)
{
action.Invoke();
}
public void WriteInt(int integer)
{
Debug.WriteLine("int:{0}", integer);
}
}
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();
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