How can I chain methods depending on user input? - c#

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.

Related

Is it possible to infer this generic type, for type-safe callback?

Is there a way to get rid of the CS0411 error below, and not have to explicitly state the type?
Also do not want to have to use reflection.
var router = new ExampleRouter();
var controller = new ExampleWebController();
// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);
// error CS0411: can't infer type
router.MapPost("/api/foo", controller.ProcessString);
class ExampleWebController {
public ExampleWebController() { }
public bool ProcessNumber(int v) { return true; }
public bool ProcessString(string v) { return true; }
}
class ExampleRouter {
public ExampleRouter() { }
public void MapPost<TBody>(string path, Func<TBody, bool> handler) {
// Save typeof(TBody), since TBody will actually be a class type we
// will construct for each callback
var body_type = typeof(TBody);
}
}
Yep, as someone's mentioned in comments one solution is to pass in the data as a parameter:
public void MapPost<TBody>(string path, Func<TBody, bool> handler, Tbody data) {
object dataType = data.GetType();
}
The reason your code is "inelegant" as you've said, is because the order of your generic arguments specifies an input type (TBody) and an output type (bool). However, in your calls to MapBody, you are only providing methods that return boolean results, so that the compiler doesn't know what to use for the value of TBody.
This is the origin of the CS0411 error you are receiving. The only way around it is to provide a generic type argument at the point of call.
This is why this code works, and should be what you use going forward:
var router = new ExampleRouter();
var controller = new ExampleWebController();
// compiles, but not elegant
router.MapPost<string>("/api/bar", controller.ProcessString);
A bit of a self answer here. If I change it to this, the MapPost() code looks elegant, which was my goal. HOWEVER, I have lost some compile time checking -- for example anything can be passed in as a "handler". I will post a new question on how I refine this.
var router = new ExampleRouter();
var controller = new ExampleWebController();
// We will have to do runtime validation that controller.ProcessString is a
// legal callback (which isn't ideal, but still fine).
// An improvement would be to add some kind of generic constraints?
router.MapPost("/api/foo", controller.ProcessString);
class ExampleWebController {
public ExampleWebController() { }
public bool ProcessNumber(int v) { return true; }
public bool ProcessString(string v) { return true; }
}
class ExampleRouter {
public ExampleRouter() { }
public void MapPost<TFunc>(string path, TFunc handler) {
var func_type = typeof(TFunc);
Console.WriteLine(func_type); // Prints "System.Func"
var args = func_type.GetGenericArguments();
foreach (var arg in args) {
// Prints "System.String", "System.Boolean"...awesome
Console.WriteLine(arg);
}
}
}

universal Thread method

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();
}

Add methods to Func

I have a list of Func and I want to add elements.
If I add them on Start like below, no problem:
public List<System.Func<bool>> conditions = new List<System.Func<bool>>();
void Start()
{
conditions.Add(Iamdead);
conditions.Add(Iamalive);
}
bool Iamdead()
{
...
return ...;
}
bool Iamalive()
{
...
return ...;
}
But I want to define the list without Start so that I have a clean list of methods that I can see as elements in a row. I have tried the classic format:
public List<System.Func<bool>> conditions = new List<System.Func<bool>>()
{
bool Iamdead()
{
...
return ...;
}
,
bool Iamalive()
{
...
return ...;
}
};
This gave me parsing error
I tried like that:
public List<System.Func<bool>> conditions = new List<System.Func<bool>>()
{
Iamdead,Iamalive
};
static bool Iamdead()
{
...
return ...;
}
static bool Iamalive()
{
...
return ...;
}
This worked only if the methods are static but I do not want them to be static. Without static, it doesn't work. It seems I couldn't understand the data structure here. Can anyone tell me the correct way of defining Func in a list?
Thanks
I strongly suspect the problem is that you're trying to access this (implicitly) within a field initializer. You're not allowed to do that. Just move the initialization into a constructor:
// You don't really use public fields, do you?
private readonly List<Func<bool>> conditions;
public MyClass()
{
conditions = new List<Func<bool>> { Method1, Method2 };
}
private bool Method1() { ... }
private bool Method2() { ... }
(I'm assuming you actually want your conditions to depend on state within the instance. If they don't, you don't need this. If the methods aren't used other than for these conditions, and they're short enough, you might want to use lambda expressions instead.)
Like so:
public List<System.Func<bool>> conditions = new List<System.Func<bool>>()
{
() => false,
() => true,
};
You can just use lambdas:
public List<System.Func<bool>> conditions = new List<System.Func<bool>>()
{
() =>
{
return false;
}
,
() =>
{
return true;
}
};

Extension Methods with variable number of parameters

I have created this helper class RichTextBoxHelper that has an extension method, and I would like to write another WriteLine method or rewrite this one (which solution is best) in order to be able to use it in the function presented under it. Thank you.
public static class RichTextBoxHelper
{
public static void WriteLine(this RichTextBox txtLog, object line)
{
txtLog.AppendText(line + Environment.NewLine);
}
}
private void selectToolStripMenuItem_Click(object sender, EventArgs e)
{
var vehicles = new List<Tuple<string, string, int>>
{
Tuple.Create("123","VW",1999),
Tuple.Create("234","Ford",2009),
Tuple.Create("567","Audi",2005),
Tuple.Create("678","Ford",2003),
Tuple.Create("789","Mazda",2003),
Tuple.Create("999","Ford",1965)
};
var fordCars = vehicles.Where(v => v.Item2 == "Ford")
.Select(v => new Car
{
VIN = v.Item1,
Make = v.Item2,
Year = v.Item3
});
foreach (var item in fordCars)
txtLog.WriteLine("Car VIN:{0} Make:{1} Year:{2}", item.VIN, item.Make, item.Year);
}
Yep, that's completely possible. It's called method overloading and it works just as well on extension method classes as normal classes.
The signature you require for your new method is:
public static void WriteLine(
this RichTextBox txtLog,
string format,
params object[] args)
{
// ...
}
Just put it in the same class as your other one and you'll be able to use both as appropriate.
Alternatively you can call your existing method in the following way:
txtLog.WriteLine(
String.Format(
"Car VIN:{0} Make:{1} Year:{2}",
item.VIN,
item.Make,
item.Year));
I think dav_i answer is correct but I prefer you to write your extension method for IsIn method something like below, because you can use it everywhere for every different kind of variables:
public static class ExtensionMethods
{
public static bool IsIn<T>(this T keyObject, params object[] collection)
{
return collection.Contains(keyObject);
}
}
usage of method is like here:
if (intValue.IsIn( 2, 3, 7 ))
{
do something...
}
if (stringVlaue.IsIn("a","b","c"))
{
do something...
}

Way to get around stack size

So I have this recursive factorial function in c#. I am using it to deal with BigInteger. The problem arises when I want to deal with large integers and because my function is recursive it will cause a StackOverflow exception. Now the simple solution is to not make the function recursive. I am wondering if there is a way to get around this? I'm thinking along the lines of more ram allocated the the stack?
BigInteger Factorial(BigInteger n)
{
return n == 1 ? 1 : n * Factorial(n - 1);
}
I understand it is nice if you could express recursive functions in c# without worrying about the stack. But unfortunately that is not directly possible, and no matter how big you make the stack there will always be situations where you run out of stack space. Furthermore your performance will likely be pretty horrendous. If you have a tail recursive function like this factorial something can be done, that pretty much lets you express your function in the original recursive way, without the huge penalty.
Unfortunately c# does not directly support tail recursive calls, but workarounds are possible using a so-called "trampoline" construction.
See for example: http://bartdesmet.net/blogs/bart/archive/2009/11/08/jumping-the-trampoline-in-c-stack-friendly-recursion.aspx and http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/
From the last blog, comes the following code that will allow you to perform the factorial as a tail recursive function without stack problems.
public static class TailRecursion
{
public static T Execute<T>(Func<RecursionResult<T>> func)
{
do
{
var recursionResult = func();
if (recursionResult.IsFinalResult)
return recursionResult.Result;
func = recursionResult.NextStep;
} while (true);
}
public static RecursionResult<T> Return<T>(T result)
{
return new RecursionResult<T>(true, result, null);
}
public static RecursionResult<T> Next<T>(Func<RecursionResult<T>> nextStep)
{
return new RecursionResult<T>(false, default(T), nextStep);
}
}
public class RecursionResult<T>
{
private readonly bool _isFinalResult;
private readonly T _result;
private readonly Func<RecursionResult<T>> _nextStep;
internal RecursionResult(bool isFinalResult, T result, Func<RecursionResult<T>> nextStep)
{
_isFinalResult = isFinalResult;
_result = result;
_nextStep = nextStep;
}
public bool IsFinalResult { get { return _isFinalResult; } }
public T Result { get { return _result; } }
public Func<RecursionResult<T>> NextStep { get { return _nextStep; } }
}
class Program
{
static void Main(string[] args)
{
BigInteger result = TailRecursion.Execute(() => Factorial(50000, 1));
}
static RecursionResult<BigInteger> Factorial(int n, BigInteger product)
{
if (n < 2)
return TailRecursion.Return(product);
return TailRecursion.Next(() => Factorial(n - 1, n * product));
}
}
You can create a new thread with the stacksize you want...
var tcs = new TaskCompletionSource<BigInteger>();
int stackSize = 1024*1024*1024;
new Thread(() =>
{
tcs.SetResult(Factorial(10000));
},stackSize)
.Start();
var result = tcs.Task.Result;
But as mentioned in comments, an iterative way for this would be better..

Categories

Resources