![](/img/trans.png)
[英]How to run variable number of methods depending on user input in Windows Forms
[英]How can I chain methods depending on user input?
我有一種用於處理圖像的方法(旋轉、過濾、調整大小等)。 它看起來像這樣:
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);
}
}
}
由於我以這種方式使用 Func<> 我可以像這樣調用我想要的編輯方法:
_imageEditor.ProcessImage(_image, im => im.Resize(size))
這意味着我可以鏈接方法,例如:
_imageEditor.ProcessImage(_image, im => im.Resize(size).Rotate(54).Flip(true))
我的問題是,如何根據使用輸入鏈接這些方法? 因此,如果我的用戶想要同時旋轉和調整大小,我可以添加 .Resize 和 .Rotate 方法(順便說一下,它們采用不同的參數)。
當然,我可以使用一堆布爾值,但如果我有大量的編輯方法,那將變得不可能,使用起來非常非常難看。
有沒有辦法將方法添加到這個鏈中,如果是這樣,你會如何 go 呢?
你的問題不是100%清楚。 你遺漏了很多細節。 但是,聽起來您要么在詢問如何連續調用您的方法,將結果從一次調用傳遞到下一次,或者如何使用在運行時創建的輸入來創建此調用列表,或兩者兼而有之。
如果沒有Minimal, Reproducible Example ,我沒有任何好的方法來重現您的場景,也沒有提供特定於該場景的解決方案。 但是,這里展示了您可以用來實現這些目標的基本技術:
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; }
}
上面有兩個關鍵要素:
Func<A, A>
委托,可以通過一個簡單的循環將它們鏈接在一起。 請參閱Chain()
方法以了解如何做到這一點。Func<A, A>
委托的序列。 實際上有很多可能的方法來解決這個特定問題。 我的示例展示了一種非常簡單的技術,使用字典將輸入string
值映射到輔助方法,這些輔助方法執行生成序列元素的實際工作。 請參閱OpsToDelegates()
。將這兩者結合到這個簡單的程序中,您可以看到如何僅從操作名稱列表和應用它們的參數列表開始,然后將其轉換為實際應用於 object 的功能操作序列。
我相信您可以將這些一般想法應用到您的特定場景中。
將方法鏈接在一起的最簡單方法是使用Aggregate
LINQ 方法。
您只需將方法簽名更改為Image ProcessImage(Image image, params Func<ImageFactory, ImageFactory>[] processes)
,然后您可以執行以下操作:
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);
}
}
}
現在您只需要根據用戶的選擇構建您的Func<ImageFactory, ImageFactory>[] processes
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.