簡體   English   中英

如何根據用戶輸入鏈接方法?

[英]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; }
}

上面有兩個關鍵要素:

  1. 給定一系列Func<A, A>委托,可以通過一個簡單的循環將它們鏈接在一起。 請參閱Chain()方法以了解如何做到這一點。
  2. 給定一些用戶輸入,可以將其轉換為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM