Dynamic length of generic parameters - c#

I've written a method that gets an array of objects, the types of the array contents as generics and tries to cast each type to the delivered generic:
public static void GetMultipleObjectsFromParameters<T, U>(
object parameterArray, out T parameter1, out U parameter2)
{
parameter1 = default(T);
parameter2 = default(U);
try
{
object[] arr = parameterArray as object[];
if (arr == null)
{
Debug.WriteLine("array not valid");
return;
}
if (arr.Length != 2)
{
Debug.WriteLine("arr.Length != 2");
return;
}
parameter1 = (T)arr[0];
parameter2 = (U)arr[1];
}
catch (Exception ex)
{
Debug.Write(ex);
}
}
I thought this method could be very useful if I use a BackgroundWorker and want to deliver more than one argument of different types (e.g. first parameter as string, second as integer...).
Now I've just wondered if there is a way to write this method without forcing a fixed size of parameters. This would prevent me from writing a method like this for each count of parameters.
I hope the question was comprehensible. Is there an easy approach? Thank you for your help.

EDIT: This answer addresses the original question rather than the motivation behind it. In terms of passing work to a BackgroundWorker etc, using a lambda expression makes perfect sense.
Now I've just wondered if there is a way to write this method without forcing a fixed size of parameters.
Nope, I'm afraid not. What you're looking for is higher order types, I think1 - but they don't exist in .NET (which is why there are so many "generic arity overloads" for Func<>, Tuple<>, Action<> etc).
1 I don't know much about these things myself, to be honest. Joe Duffy has a blog post which blows my mind somewhat, but which may be useful.

if there is a way to write this method without forcing a fixed size of parameters
You don't need to write this method with variable size of parameters. You need Tuple:
var myParams = Tuple.Create(100, "Hello, world!");
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
var arg = (Tuple<int, string>)args.Argument;
if (arg.Item2.Length > 5)
{
var foo = arg.Item1 + 200;
}
// etc ...
};
worker.RunWorkerAsync(myParams);
or lambdas with closures:
var someIntParam = 100;
var someStringParam = "Hello, world!";
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
if (someStringParam.Length > 5)
{
var foo = someIntParam + 200;
}
// etc ...
};
worker.RunWorkerAsync();
It depends on how do you use BackgroundWorker in your real code.

Related

How to run variable number of methods depending on user input in Windows Forms

I am struggling with the concept described below:
User checks x of 5 checkboxes with type of measurements and then he clicks "RUN".
On the "RUN" OnClick() I create a Measure class object.
class Measure
{
string measure_type;
SendCommandToArduino(string nameOfMeasurement)
...
}
I need to run those selected methods IN SEQUENCE (they CANNOT run asynchronous, because they use Serial COM).
I hardcoded something like this:
void Method1()
{
measurement.SendCommandToArduino("tetnienie");
}
void Method2()
{
measurement.SendCommandToArduino("jasnosc");
}
tPomiar1 = new Thread(Method1);
tPomiar1.Start();
tPomiar1.Join();
pomiar.DrawGraphTetnien(tetnienie_Chart);
tPomiar2 = new Thread(Method2);
tPomiar2.Start();
tPomiar2.Join();
MessageBox.Show("Done all measurements!");
No surprise - it worked. But:
I still don't know how to relate number of checked checkboxes with number of methods to run in these threads. Maybe I should hardcode MethodX for all measurements and then run threads from some List list_of_threads?
Threads are overkill for this purpose ( I guess ), cause the longest measurement takes about 10 seconds... Is there any other way?
ThreadPool, Tasks, async/await ? I am totally new to multi-tasking/threading
I also tried something like this, but I didn't finish this solution, it was too hardcore:
List<Thread> list_of_threads= new List<Thread>();
List<Action> measureToDo = new List<Action>();
// link those additions with checkboxes
measureToDo.Add(Method1);
measureToDo.Add(Method2);
measureToDo.Add(Method3);
int i = 0;
foreach (Action action in measureToDo)
{
//substring this one to get method's name!
string methodName = action.Method.Name.ToString());
methodName = methodName.Substring(4,6) // limit of 9 methods here haha
}
foreach (var item in measureToDo )
{
RunThread(item.Method.Name.ToString());
}
void RunThread(Action a)
{
Thread t;
t = new Thread(new ThreadStart(a.Method.Name)).Start();
}
For a measure_type I created a '5-bit' string -> Containg "1" if the checkbox on this position was checked.
"01000" / "10011" etc.
Thank You in advance for all hints/tips! :)
Perhaps you are overcomplicating things, and a simple solution would be perfectly well.
You can use Control.Tag property and add the name (as string) of the measure to everyone of your checkboxes. Then, you can enumerate your check-boxes, see which is checked, and get a list of strings with the names of the measures you need to perform.
Then, you need a single method to execute your measures. It should enumerate the list, and have a switch to map a measure to a method:
void ExecuteMeasures(List<string> measures)
{
foreach (string measure in measures)
{
switch (measure)
{
case "Measure 1": MeasureMethodOne(); break;
// and so on...
}
}
}
Then you don't need to run each measure method in a separate thread, because you want them to be executed sequentially. You only need to run the ExecuteMeasureMethod in a separate thread. Having it run for seconds, a separate thread is fine. Still, to keep things neat, use a long running task:
var listOfMeasures = new List<string>();
//Populate your list from the selection of check boxes
Task t = Task.StartNew ( ()=> ExecuteMeasures(listOfMeasures), TaskCreationOptions.LongRunning);
await t;
Here is my solution:
1. Define a Action array to store your methods
2. Get the values of checked items(checkbox1's value is 0, etc.) as the array indices
3. Invoke the relevant method in the array.
Codes are something like :
public static void Main()
{
Action[] actions = new Action[5];
actions[0] = Method1;
actions[1] = Method2;
string checkedValue = "1";
actions[int.Parse(checkedValue) - 1].Invoke();
}
static void Method1()
{
Console.WriteLine(1);
}
static void Method2()
{ }
Or you can simplify the code as below:
public static void Main()
{
Action[] actions = new Action[5];
actions[0] = ()=> { Console.WriteLine(1); };
actions[1] = ()=> { Console.WriteLine(2); };
string checkedValue = "1";
actions[int.Parse(checkedValue) - 1].Invoke();
}

Polymorphic way to call different functions with an allocated thread

I have a class with a set of functions that differ in the number of parameters and the parameter types. I've been trying to figure out a way to invoke a call to a desired function inside an allocated thread.
What's a simple way of doing this? I've looked into System.Action, but that requires the parameters to be known. I've also gone over TaskFactory and TPL, but from the examples I've seen, I can't put together the solution in my head.
What I want to eventually do is queue up jobs that will be executed by a limited number of threads. The jobs performed are simple HTTP requests.
I feel like this has been done before and has a simple solution, but it has eluded me for weeks. I'm hoping for an elegant way of doing it instead of a lot of complex code.
I'm also trying to implement MEF plugins to make matters worse.
public bool AddThreads(int numOfThreads)
{
try
{
// Exit if no plugin type is set
if (PluginType == "") return false;
int totalThreads = numOfThreads + threads.Count;
for (int i = threads.Count; i < totalThreads; i++)
{
// Create an instance of the MEF plugin
var task = PluginHandler.CreateInstance(PluginType);
threads.Add(task);
task.ThreadId = i;
task.OnStatusChange += new TaskerPlugin.EventHandler(ChangeStatus);
task.OnActionComplete += new TaskerPlugin.EventHandler(ReportComplete);
task.OnActionSuccess += new TaskerPlugin.EventHandler(ReportSuccess);
task.OnActionFailure += new TaskerPlugin.EventHandler(ReportFailure);
task.OnActionAttempt += new TaskerPlugin.EventHandler(ReportAttempt);
task.OnActionError += new TaskerPlugin.EventHandler(ReportError);
task.OnActionCancelled += new TaskerPlugin.EventHandler(ReportCancellation);
task.OnActionBegin += new TaskerPlugin.EventHandler(ReportStartOfTask);
task.OnActionEnd += new TaskerPlugin.EventHandler(ReportEndOfTask);
// Do work from plugin
// This is where I'd like to call different
// functions possibly inside Start()
task.Start();
}
return true;
}
catch (Exception)
{
return false;
}
}
Current code calling the function:
private void CreateThreads(int threadCount)
{
// taskMan is a class variable to queue more jobs in the future
taskMan = new TaskManager(PLUGIN_FOLDER)
{
PluginType = PLUGIN_TYPE,
UseProxies = (_config.IpSolution == "Proxies" || _config.IpSolution == "Proxy URL")
};
taskMan.AddThreads(threadCount);
}
I want to eventually just call a function to add a job to it with a predefined number of threads:
private void AddJob(string pluginName, string methodName, List<string> args)
I'd prefer not just using a string list to put all of my arguments in, but I don't really know of another way of doing it. Maybe a list of objects which I then cast later? Both these ideas are very messy...
I am assuming that AddJob is the overloaded method that you need to call with different parameters.
You might have to tweak your PluginHandler.CreateInstance(PluginType) method to do something like this while creating the task, this would allow you to execute any method you need in the task that you create..
Task task = new Task(() =>
{
classInstance.YourMethod("some param1", some other param2));
}
Further with some reflection..
var classInstance = new YourClass();
Type type = classInstance.GetType();
MethodInfo methodInfo = type.GetMethod("AddJob");
object[] parametersArray = new object[] { "some param1", "some parma2" };
methodInfo.Invoke(methodInfo, parametersArray);
and finally,
Task task = new Task(() =>
{
var classInstance = new YourClass();
Type type = classInstance.GetType();
MethodInfo methodInfo = type.GetMethod("AddJob");
object[] parametersArray = new object[] { "some param1", "some parma2" };
methodInfo.Invoke(classInstance, parametersArray);
}
In case the AddJob method is present in the current class itself, there could be little changes to the code.

Try-catch until success - execution loop for generic methods or delegates

I want my code to keep trying a method until no exception is thrown, however, unlike this question, I would like it to be written as a generic method capable of running any input delegate/method. Here is what I've had in mind, but I am not sure how to pass the arguments or generic methods through it:
public void tryLoop(Delegate anyMethod, T[] arguments) {
while (true) {
// Could be replaced by timer timeout
try {
anyMethod(arguments);
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Is this possible?
EDIT: For the academics of it, I would also be curious to know if it's possible to return the result as well.
If you can settle for using closures, you won't need to have to pass parameters to this method all (or have multiple overloads). The result can be returned using a Func.
public T tryLoop<T>(Func<T> anyMethod)
{
while (true)
{
try
{
return anyMethod();
}
catch
{
System.Threading.Thread.Sleep(2000); // *
}
}
return default(T);
}
void SomeMethod(int param)
{
var someLocal = "Hi";
var anotherLocal = 0;
var result = tryLoop(() =>
{
Console.WriteLine(someLocal);
return param + anotherLocal;
});
Console.Write(result);
}
To be honest, I wouldn't set an infinite retry, however - at best, if certain types of retryable error were returned, such as a database deadlock, or a timeout calling an erratic web service, then possibly 3 or 4 retries might be in order. Exceptions such DivideByZero or FileNotFound aren't likely to go away by running them indefinitely :-)
*** especially with deadlocks, sleeping for a random period is recommended, just in case other threads are also simultaneously deadlocking on exactly the same data - you don't want the same deadlock recurrence happening in 2000ms :-).
A way to do this is by using an Action, and remove the arguments parameter:
public void tryLoop(Action anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
anyMethod();
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
This gives you ultimate freedom in how to use it:
tryLoop(() => string.Reverse("abc"));
or like this:
String s1 = "A";
String s2 = "b";
tryLoop(() => string.Concat(s1, s2));
As you can see in the second example, you can directly take the arguments from the context of the tryLoop method being called. You can invoke anything there.
The good thing for this approach is that you will not have to use Invoke or DynamicInvoke as with a Delegate instead of Action, because these introduce a performance penalty.
If you need the result, you can re-write the above with a Func<T> instead of Action, like this:
public T tryLoop<T>(Func<T> anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
return anyMethod();
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
and use it like this:
var reversed = tryLoop(() => string.Reverse("abc"));
String s1 = "A";
String s2 = "b";
var concatenated = tryLoop(() => string.Concat(s1, s2));
Check if this suit your needs. If not then please comment. Also not sure how it will be performance wise.
Also the DynamicInvoke method has an object return type. This you can use to return the result of the delegate. You can change the return type of method from void to object.
public void tryLoop<T>(Delegate anyMethod, T[] arguments)
{
while (true)
{ // Could be replaced by timer timeout
try
{
anyMethod.DynamicInvoke(arguments);
break;
}
catch
{
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Hope this helps

WPF C# Threading

I am writing a code in c# to do image processing. I want to use threading and i suppose threading in WPF application is little different. I tried to run thread but it only works when the function is void(), i.e does not take any arguments.
However, my function is taking 3 arguemnts like this
frame_extract.Frame_Processing(_colorFrame_, widht, height);
So therefore the following does not work
depth_Threads = new System.Threading.Thread(**) since ** takes on void() type.
perhaps i am missing something, but my question is how can i work with threading for functions that take arguments.
Maybe you could use the TPL.
It should then be something like:
Task.Factory.StartNew(() => frame_extract.Frame_Processing(_colorFrame_, widht, height));
But be aware that you might have to marshal to the ui-thread.
If you want to create the thread in the ui thread and want the new thread to interact with mentioned ui thread, something like the following should work:
var task = new Task(() => frame_extract.Frame_Processing(_colorFrame_, widht, height));
task.Start(TaskScheduler.FromCurrentSynchronizationContext());
That should work.
I'm not 100% sure if that's what you want, but I think you need to do this :
depth_Threads = new System.Threading.Thread(()=>frame_extract.Frame_Processing(_colorFrame_, widht, height));
It depends on what values you are passing in. Sometimes if you are using objects, they are locked to a given thread in which case you need to create duplicates prior and then pass the duplicates into the new thread.
Do the following. Your method should receive single object argument like this void SomeVoid(object obj). Make an object array with all variables that you want to pass to the method SomeVoid like this object[] objArr = { arg1, arg2, arg3 }; and then call the Start method of thread object with objArr argument since the Start() method receives one object parameter. Now back to your method, cast and obj received from Start method to an object array like this object arr = obj as object[]; and then you can access those 3 arguments like this arr[0] arr[1] and arr[2]
You can use the ParameterizedThreadStart class.
1) Create a class who will holds your three arguments
public class FrameProcessingArguments
{
public object ColorFrame { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
2) Modify your Frame_Processing method to take as parameter an instance of Object and inside it, cast that instance as a FrameProcessingArguments
if (arguments == null) throw new NullArgumentException();
if(arguments.GetType() != typeof(FrameProcessingArguments)) throw new InvalidTypeException();
FrameProcessingArguments _arguments = (FrameProcessingArguments) arguments;
3) Create and start your thread
FrameProcessingArguments arguments = new FrameProcessingArguments()
{
ColorFrame = null,
Width = 800,
Height = 600
}
Thread thread = new Thread (new ParameterizedThreadStart(frame_extract.Frame_Processing));
// You can also let the compiler infers the appropriate delegate creation syntax:
// and use the short form : Thread thread = new Thread(frame_extract.Frame_Processing);
thread.Start (arguments);

How to invoke a delegate with a null parameter?

I get a null exception if I try to pass a null parameter to a delegate during an invoke. Here's what the code looks like:
public void RequestPhoto()
{
WCF.Service.BeginGetUserPhoto(Contact.UserID,
new AsyncCallback(RequestPhotoCB), null);
}
public void RequestPhotoCB(IAsyncResult result)
{
var photo = WCF.Service.EndGetUserPhoto(result);
UpdatePhoto(photo);
}
public delegate void UpdatePhotoDelegate(Binary photo);
public void UpdatePhoto(Binary photo)
{
if (InvokeRequired)
{
var d = new UpdatePhotoDelegate(UpdatePhoto);
Invoke(d, new object[] { photo });
}
else
{
var ms = new MemoryStream(photo.ToArray());
var bmp = new Bitmap(ms);
pbPhoto.BackgroundImage = bmp;
}
}
The problem is with the line:
Invoke(d, new object[] { photo });
If the variable "photo" is null. What is the correct way to pass a null parameter during an invoke?
Thanks!
Just for the benefit of others, you can pass null arguments to delegates (if the type allows it? Clarification needed here). In your case, IAsyncResult will allow it.
As for the debugging, the exception occurs on Invoke because you are debugging on a given Thread A, the exception occurs on Thread B. You can breakpoint multiple threads. Breakpoint the Thread B code and you will see the exception closer to or on the source.
Notice though that your debugger will jump around if multiple threads are running code at the same time. Debugging in multiple threads is always at least a little tricky, but satisfying when you solve the problems.
You could also further improve your answer code to check the null before it checks the InvokeRequired, as this is thread-independent to your logic (your code checks it just prior to use, after Invoking). This will save pushing the Invoke onto the message pump (assuming WinForms).
OK I figured it out. The problem was NOT with passing the null parameter to the delegate like I thought. The problem was with the delegate executing it was causing a null exception on the line:
var ms = new MemoryStream(photo.ToArray());
I didn't realize the problem was there because it was crashing on the Invoke line.
So I changed the UpdatePhoto method as follows:
public void UpdatePhoto(Binary photo)
{
if (InvokeRequired)
{
var d = new UpdatePhotoDelegate(UpdatePhoto);
Invoke(d, new object[] { photo});
}
else
{
if (photo != null)
{
var ms = new MemoryStream(photo.ToArray());
var bmp = new Bitmap(ms);
pbPhoto.BackgroundImage = bmp;
}
}
}
And all is well!

Categories

Resources