Hello everyone I want to ask , is there any methods that using thread that can run every methods[B] with argument and return any kind of those methods[B] refer :
private static Image queeImageFromString (string str)
{
// bla bla
return myImage;
} ///methods B return image
private static byte[] queeImagetoBtye (string str, string b)
{
//bla bla
return myBytesArray;
} //methods B return image
//**this is the methode I want to ask**
private static dynamic RunMethods(Action action)
{
var file;
var thread = new Thread(() => { file = action; });
thread.Start();
thread.Join();
return file; //will return anything like string, image, bytearray depending on method[B] returne
/// note : this code still wrong
}
/// I want to do 'RunMethods' run like this
public static string getResultByte (string str, string b)
{
// if methods[B] return string it will return string
StringBuilder strb = new StringBuilder (RunMethods(queeImagetoBtye (str,b));
return strb.ToString();
}
public static Image getImageResult (string str)
{
//if methods[B] return Image it will return Image
Image imgs = RunMethods( queeImageFromString (str));
return imgs;
}
Thank you.
Your code isn't working cause of many reasons.
Action can't return anything, it's an action, you have to use Func
You do not call the action, just assign it, so you have to write this code: file = action();
You're creating the action from lambda wrong way, you need to do like this: () => queeImageFromString(str)
Not a major problem, but you don't have to create a StringBuilder to create a string, you can return the method result itself.
What you need is a generic method, as dynamic is very slow structure, and dealing with it always relates with a reflection, which is slow by default. You can provide the type for function to return, like this:
private static T RunMethods<T>(Func<T> f)
{
var file;
var thread = new Thread(() => { file = f(); });
thread.Start();
thread.Join();
return file; //will return anything like string, image, bytearray depending on method[B] return value
}
So the call will looks like this:
//if methods[B] return Image it will return Image
Image imgs = RunMethods<Image>(() => return queeImageFromString(str));
Maybe the call could be even more simplified, but right now I can't check that. Also you really should consider the TPL usage instead of threads.
Check if doing it another way would be suitable for you.
I would create a class containing returned values, together with some indicator saying what type of object I'm returning.
public class ReturnValues
{
public object ReturnValue;
public ReturnValueType RetType;
}
enum ReturnValueType
{
typeOfString,
typeOfImage,
typeofInt
}
public static ReturnValues queeString (object[] args)
{
//.....
return new ReturnValues{ ReturnValue="Test", RetType=ReturnValueType.typeOfString };
}
Now, instead of Action, you have to use Func.
If you have to take parameters, you have to take them in some object too, like object array object[].
public static ReturnValues RunMethods(Func<object[],ReturnValues> action)
{
var file=action;
//.....
return file;
}
public static string getResultByte (object[] args)
{
string str=(string)args[0];
string b=(string)args[1];
var initValue=RunMethods(queeString(args));
string returnedString;
if (initValue.RetType==ReturnValueType.typeOfString)
{
returnedString=(string)initValue.ReturnValue;
}
StringBuilder strb = new StringBuilder (returnedString);
return strb.ToString();
}
Related
I have a method that I'm using to process images (rotate, filter, resize, etc). It looks like this:
public Image ProcessImage(Image image, Func<ImageFactory, ImageFactory> process)
{
using (var imageFactory = new ImageFactory(preserveExifData: true))
{
using (var imageStream = new MemoryStream())
{
var loadResult = imageFactory.Load(image);
var processResult = process(loadResult);
processResult.Save(imageStream);
return Image.FromStream(imageStream);
}
}
}
Since I'm using Func<> in this way I can just call the editing method I want like so:
_imageEditor.ProcessImage(_image, im => im.Resize(size))
Which means I can chain methods like:
_imageEditor.ProcessImage(_image, im => im.Resize(size).Rotate(54).Flip(true))
My question is, how can I chain these methods depending on the using input? So if my user wants to rotate and resize at the same time, I could just add the .Resize and .Rotate methods (which by the way, take different parameters).
Sure, I could use a bunch of bools but if I had a ton of editing methods it would become impossible, very very ugly to use.
Is there a way to add methods to this chain, and if so, how would you go about it?
Your question isn't 100% clear. You've left a lot of details out. But, it sounds like you are either asking how to successively invoke your methods, passing the result from one invocation to the next, or how to use inputs created at runtime to create this list of invocations, or both.
Without a Minimal, Reproducible Example, I don't have any good way to reproduce your scenario, nor to provide a solution that is specific to that scenario. But, here's a demonstration of the basic techniques you might use to accomplish those goals:
class Program
{
private static readonly Dictionary<string, Func<int[], Func<A, A>>> _parser =
new Dictionary<string, Func<int[], Func<A, A>>>()
{
{ "Init", MakeInitFunc },
{ "Add", MakeAddFunc },
{ "Multiply", MakeMultiplyFunc },
{ "Negate", MakeNegateFunc },
};
static void Main(string[] args)
{
(string, int[])[] ops =
{
("Init", new [] { 17 }),
("Add", new [] { 5 }),
("Multiply", new [] { 2 }),
("Negate", new int[0]),
};
Console.WriteLine(Chain(new A(), OpsToDelegates(ops)).Value);
Console.WriteLine(Chain(new A(), OpsToDelegates(ops).Reverse()).Value);
}
private static IEnumerable<Func<A,A>> OpsToDelegates(IEnumerable<(string Name, int[] Args)> ops)
{
foreach (var op in ops)
{
yield return _parser[op.Name](op.Args);
}
}
private static A Chain(A a, IEnumerable<Func<A, A>> ops)
{
foreach (Func<A, A> op in ops)
{
a = op(a);
}
return a;
}
private static Func<A, A> MakeInitFunc(int[] args)
{
return a => a.Init(args[0]);
}
private static Func<A, A> MakeAddFunc(int[] args)
{
return a => a.Add(args[0]);
}
private static Func<A, A> MakeMultiplyFunc(int[] args)
{
return a => a.Add(args[0]);
}
private static Func<A, A> MakeNegateFunc(int[] args)
{
return a => a.Negate();
}
}
class A
{
public int Value { get; private set; }
public A Init(int value) { Value = value; return this; }
public A Add(int value) { Value += value; return this; }
public A Multiply(int value) { Value *= value; return this; }
public A Negate() { Value *= -1; return this; }
}
There are two key elements to the above:
Given a sequence of Func<A, A> delegates, it is possible to chain them together with a simple loop. See the Chain() method for how that can be done.
Given some user input, it is possible to transform that into a sequence of Func<A, A> delegates. There is actually a very wide range of possible ways to approach that particular problem. My example shows a very simple technique, using a dictionary that maps input string values to helper methods that do the actual work of generating the elements of the sequence. See OpsToDelegates() for that.
Combining those two into this simple program, you can see how you can start with just a list of names of operations and parameters to apply them, and turn that into a functional sequence of operations actually applied to an object.
I trust you can take these general ideas and apply them to your particular scenario.
The easiest way to chain methods together is to use the Aggregate LINQ method.
You just need to change your method signature to Image ProcessImage(Image image, params Func<ImageFactory, ImageFactory>[] processes) and then you can do this:
public Image ProcessImage(Image image, params Func<ImageFactory, ImageFactory>[] processes)
{
using (var imageFactory = new ImageFactory(preserveExifData: true))
{
using (var imageStream = new MemoryStream())
{
var loadResult = imageFactory.Load(imageStream);
var processResult = processes.Aggregate(loadResult, (r, p) => p(r));
processResult.Save(imageStream);
return Image.FromStream(imageStream);
}
}
}
Now you just have to build your Func<ImageFactory, ImageFactory>[] processes from the user's selections.
I am working on creating an app just like the Output Terminal (Unix) or the Command Line Prompt (Windows). I have created a dictionary that has some keywords for a function. But when I call those keywords, nothing is done. My program is called Command Line Control (or CLC). And I use the .NET Core which is for all running software(Linux, macOS, and Windows).
I do not know what to try exactly. A function is a function. It must be executed when I call it.
using System;
using System.Collections.Generic;
using System.Threading;
using System.IO;
namespace CLC
{
class Program
{
static DirectoryInfo maindirectory;
static Dictionary<string, string> keyaction;
static string value;
static void WritePathOfWorkingDirectory(DirectoryInfo directory)
{
if (directory != null)
{
Console.Write("{0}:", directory.FullName);
}
else
{
}
}
static void ProcessAnswer(string[] array)
{
string action = array.GetValue(0).ToString();
value = array.GetValue(1).ToString();
string c = keyaction[action];
Console.Write(c);
}
static string ListFiles()
{
foreach(var file in maindirectory.GetFiles())
{
Console.WriteLine(file.Name);
}
return "ok";
}
static string ListDirectories()
{
foreach(var directory in maindirectory.GetDirectories())
{
Console.WriteLine(directory);
}
return "ok";
}
static void MainProgramm()
{
WritePathOfWorkingDirectory(maindirectory);
string data = Console.ReadLine();
var arry = data.Split(' ');
ProcessAnswer(arry);
Thread repeat = new Thread(MainProgramm);
repeat.Start();
}
static void Main(string[] args)
{
maindirectory = new DirectoryInfo("C:/Users");
keyaction = new Dictionary<string, string>();
keyaction.Add("lf", ListFiles());
keyaction.Add("ld", ListDirectories());
Console.Clear();
maindirectory = new DirectoryInfo("C:/Users");
Thread thread = new Thread(new ThreadStart(MainProgramm));
thread.Start();
}
}
}
The expected result is to do what the key says: for example if I type ld (list directories) the list directory function should be executed. But I don't get anything! The program just repeats itself.
When you include the parentheses after a Method name, you invoke the method. So rather than passing the function as the Dictionary value, you're passing the result of calling that function. You need to get a reference to the function to be called then invoke it.
Your Main method should look like this:
static void Main(string[] args)
{
maindirectory = new DirectoryInfo("C:/Users");
keyaction = new Dictionary<string, Func<string>>(); // changed this to an Func instead of a string
keyaction.Add("lf", ListFiles); // notice I removed the parentheses here
keyaction.Add("ld", ListDirectories); // and here
Console.Clear();
maindirectory = new DirectoryInfo("C:/Users");
Thread thread = new Thread(new ThreadStart(MainProgramm));
thread.Start();
}
and keyaction should be declared like this:
static Dictionary<string, Func<string>> keyaction; // a Func<string> is a function that returns a string and takes no arguments
Then, in your ProcessAnswer method you need to call the function via the reference you have to it in the Dictionary:
static void ProcessAnswer(string[] array)
{
string action = array.GetValue(0).ToString();
value = array.GetValue(1).ToString();
string c = keyaction[action](); // calling the referenced funtion
Console.Write(c);
}
This should give you the expected result.
In the current state, your program's methods only get called once and then you clear the Console before you can see the output, so it probably looks like your program just says "ok" whenever you enter a command.
The main problem is that you're storing a string value in the dictionary rather than the function itself, so when you add the functions, you're adding their immediate return value (before you ever prompt the user for input).
Instead, the dictionary value should be a Func<string>, which you can then .Invoke on demand.
Additionally, it seemed that you weren't validating the user entry. We can use TryGetValue for the user's entry to ensure that they entered a valid command (if it exists in the dictionary). If it doesn't, we can tell them their input was invalid.
Also, when accessing array values, you should first ensure that the index you're accessing is valid (if the user only enters one command, like "lf"with no value, then you can't access array index [1] because it doesn't exist.
Also, it seems like even when the user does input a path, you store it in value, but never use it. So I modified the ListFiles and ListDirectories methods to treat the value as a path, and if it exists, list the files or directories from the path specified.
Try out this code with the changes:
public class Program
{
private static DirectoryInfo _maindirectory = new DirectoryInfo("C:\\Users");
private static Dictionary<string, Func<string>> _keyaction =
new Dictionary<string, Func<string>>
{
{"lf", ListFiles},
{"ld", ListDirectories},
{"cd", ChangeDirectory},
{"exit", Exit}
};
private static string _value;
private static void DisplayPrompt(FileSystemInfo directory)
{
Console.Write($"{directory?.FullName ?? "[cmd]"}: ");
}
private static void ProcessAnswer(IReadOnlyList<string> array)
{
var action = array.Count > 0 ? array[0] : string.Empty;
_value = array.Count > 1 ? array[1] : null;
Func<string> method;
_keyaction.TryGetValue(action, out method);
if (method == null)
{
WriteError($"Unknown command: {action}");
}
else
{
Console.WriteLine(_keyaction[action].Invoke());
}
}
private static string ListFiles()
{
var dir = Directory.Exists(_value) ? new DirectoryInfo(_value) : _maindirectory;
foreach (var file in dir.GetFiles())
{
Console.WriteLine(file.Name);
}
return "ok";
}
private static string ListDirectories()
{
var dir = Directory.Exists(_value) ? new DirectoryInfo(_value) : _maindirectory;
foreach (var directory in dir.GetDirectories())
{
Console.WriteLine(directory);
}
return "ok";
}
private static string ChangeDirectory()
{
if (Directory.Exists(_value))
{
_maindirectory = new DirectoryInfo(_value);
}
else if (Directory.Exists(Path.Combine(_maindirectory.FullName, _value)))
{
_maindirectory = new DirectoryInfo(
Path.Combine(_maindirectory.FullName, _value));
}
else
{
WriteError("Directory not found.");
}
return "ok";
}
private static void WriteError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ResetColor();
}
private static string Exit()
{
Environment.Exit(0);
return "ok";
}
private static void Main()
{
while (true)
{
DisplayPrompt(_maindirectory);
ProcessAnswer(Console.ReadLine()?.Split(' '));
}
}
}
In order to reduce the amount of code our team put in a StartProcess method to call the WCF implementation for all calls from a single method. It all works great, but since the actual call from the generic method uses a System.Action to invoke, it can never return a value and since one of the calls I am making I would like to make a request/reply, I can't get that return value.
Here is the Generic method to handle the WCF requests:
public static ProcessResultDC StartProcess<T>(T setupData, string processName, Action<T> action, string exteriorAccountNumber, string companyCode) where T : IAmValidatable, IHaveAProcessGuid {
var result = new ProcessResultDC { Status = ProcessStatusEnum.Accepted };
// Do some authentication stuff here
try {
action(setupData); // <-- This returns void, but I would like to return a string to the client
} catch (Exception exc) {
result.Status = ProcessStatusEnum.Error;
result.Messages.Add(exc.Message);
}
return result;
}
And here is the client call:
var createOnDemandDataDc = new CreateOnDemandDataDc { RawData = punchRawData };
var result = TimeForceProcessHelper.StartProcess(createOnDemandDataDc, "Create On Demand Data", x => new CreateOnDemandDataProxy().CreateOnDemandData(createOnDemandDataDc), "NA", companyCode);
The result variable has no way of knowing about the string from the action call, even though my createOnDemandDataDc implementation returns a string.
Is there a better way to do this? Or can I simply do something other than an Action() call in order to get the return string?
Instead of using Action<T> for the callback param, you could use Func<T, TResult> to allow the callback to return a value to the StartProcess caller. However, this will require that all your callbacks would need to be changed to functions that return a value. Probably not a happy thought if you only have one callback that needs to return a reply.
Another somewhat dirty approach might be to write your response to the currently active OperationContext directly in your CreateOnDemandDataDc callback function. Look at OperationContext.Current.RequestContext.Reply and related properties/methods.
This is how I do AOP too. You need two methods for each aspect - one for an Action and one for a Func
If you write the one for Func first:
public static ProcessResultDC StartProcess<T, TResult>(
T setupData,
string processName,
Func<T, TResult> fn,
string exteriorAccountNumber,
string companyCode
)
where T : IAmValidatable, IHaveAProcessGuid
{
var result = new ProcessResultDC { Status = ProcessStatusEnum.Accepted };
// Do some authentication stuff here
try
{
result.Result = fn(setupData);
}
catch (Exception exc)
{
result.Status = ProcessStatusEnum.Error;
result.Messages.Add(exc.Message);
}
return result;
}
Then you can write the one for Action to use the Func implementation:
public static ProcessResultDC StartProcess<T>(
T setupData,
string processName,
Action<T> fn,
string exteriorAccountNumber,
string companyCode
)
where T : IAmValidatable, IHaveAProcessGuid
{
return StartProcess(
setupData,
processName,
t => { fn( t ); return 0; },
exteriorAccountNumber,
companyCode
);
}
I want enqueue a list of tasks and then perform on certain event. Code:
internal class MyClass
{
private Queue<Task> m_taskQueue;
protected MyClass()
{
m_taskQueue = new Queue<Task>();
}
public delegate bool Task(object[] args);
public void EnqueueTask(Task task)
{
m_taskQueue.Enqueue(task);
}
public virtual bool Save()
{
// save by processing work queue
while (m_taskQueue.Count > 0)
{
var task = m_taskQueue.Dequeue();
var workItemResult = task.Invoke();
if (!workItemResult)
{
// give up on a failure
m_taskQueue.Clear();
return false;
}
}
return true;
}
}
Each delegate task may have their own list of parameters: Task(object[] args). My question is how to pass the parameter to each task for the task queue?
Okay, now we have a bit more information, it sounds like your EnqueueTask method should actually look like this:
public void EnqueueTask(Task task, object[] values)
Right?
For starters I would avoid using the name Task, which is already part of the core of .NET 4 and will become very prominent in .NET 5. As Joshua said, you've basically got a Func<object[], bool>.
Next, you could keep two lists - one for the delegates and one for the values, but it's easier just to keep a Queue<Func<bool>> like this:
private readonly Queue<Func<bool>> taskQueue = new Queue<Func<bool>>();
public void EnqueueTask(Task task, object[] values)
{
taskQueue.Enqueue(() => task(values));
}
Then the rest of your code will actually work "as is". The lambda expression there will capture values and task, so when you invoke the Func<bool>, it will supply those values to the original delegate.
Provided understanding your question correctly you just pass the information like a normal call. Have you considered using Func? You can just pass arguments to the Task.Invoke i.e. Task.Invoke([arguments here as a *single* object array]).
object[] arguments = null; // assign arguments to something
var workItemResult = task.Invoke(arguments);
Below is an example with the Func type.
internal class MyClass
{
private Queue<Func<object[], bool>> m_taskQueue;
protected MyClass()
{
m_taskQueue = new Queue<Func<object[], bool>>();
}
public void EnqueueTask(Func<object[], bool> task)
{
m_taskQueue.Enqueue(task);
}
public virtual bool Save()
{
object[] arguments = null; // assign arguments to something
// save by processing work queue
while (m_taskQueue.Count > 0)
{
var task = m_taskQueue.Dequeue();
var workItemResult = task(arguments);
if (!workItemResult)
{
// give up on a failure
m_taskQueue.Clear();
return false;
}
}
return true;
}
}
I've this little method which is supposed to be thread safe. Everything works till i want it to have return value instead of void. How do i get the return value when BeginInvoke is called?
public static string readControlText(Control varControl) {
if (varControl.InvokeRequired) {
varControl.BeginInvoke(new MethodInvoker(() => readControlText(varControl)));
} else {
string varText = varControl.Text;
return varText;
}
}
Edit: I guess having BeginInvoke is not nessecary in this case as i need value from GUI before the thread can continue. So using Invoke is good as well. Just no clue how to use it in following example to return value.
private delegate string ControlTextRead(Control varControl);
public static string readControlText(Control varControl) {
if (varControl.InvokeRequired) {
varControl.Invoke(new ControlTextRead(readControlText), new object[] {varControl});
} else {
string varText = varControl.Text;
return varText;
}
}
But not sure how to get value using that code either ;)
You have to Invoke() so you can wait for the function to return and obtain its return value. You'll also need another delegate type. This ought to work:
public static string readControlText(Control varControl) {
if (varControl.InvokeRequired) {
return (string)varControl.Invoke(
new Func<String>(() => readControlText(varControl))
);
}
else {
string varText = varControl.Text;
return varText;
}
}
EndInvoke may be used to get a return value from a BeginInvoke call. For example:
public static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asychronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// Call EndInvoke to wait for the asynchronous call to complete,
// and to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
public static string readControlText(Control varControl)
{
if (varControl.InvokeRequired)
{
string res = "";
var action = new Action<Control>(c => res = c.Text);
varControl.Invoke(action, varControl);
return res;
}
string varText = varControl.Text;
return varText;
}
If you want a return value from you method, you shouldn't be using async version of the method, you should use .Invoke(...). Which is synchronous, that is it will execute your delegate, and won't return until it's complete. In your example as it is now, BeginInvoke will send the request to execute your delegate, and return right away. So there is nothing to return.
Is something like this what you wanted?
// begin execution asynchronously
IAsyncResult result = myObject.BeginInvoke("data.dat", null, null);
// wait for it to complete
while (result.IsCompleted == false) {
// do some work
Thread.Sleep(10);
}
// get the return value
int returnValue = myObject.EndInvoke(result);
delegate string StringInvoker();
string GetControlText()
{
if (control.InvokeRequired)
{
string controltext = (string)control.Invoke(new StringInvoker(GetControlText));
return(controltext);
}
else
{
return(control.Text);
}
}
//simple & elegant but it is needed to wait for another thread to execute delegate; however if you cannot proceed without the results...
Here is more cleaner solution
public delegate void InvokeIfRequiredDelegate<T>(T obj) where T : ISynchronizeInvoke;
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
obj.Invoke(action, new object[] { obj });
else
action(obj);
}
public static string GetThreadSafeText(this Control control)
{
string value = string.Empty;
control.InvokeIfRequired((c) => value = c.Text);
return value;
}
public static void SetThreadSafeText(this Control control, string value)
{
control.InvokeIfRequired((c) => c.Text = value);
}
Usage:
public string Name
{
get => txtName.GetThreadSafeText();
set => txtName.SetThreadSafeText(value);
}