在C#中创建一个上下文组,以将多个操作绑定为一个

时间:2018-09-05 07:17:39

标签: c# algorithm

我需要产生彼此不知道但可以分为执行组之类的单个动作。各个动作也被级联,因此也存在多个层次结构。

我只能展示一个小例子以使事情变得更清楚,并打开该例子作为讨论的起点。这个例子并不完全有意义,而是为了表明我的意图。

在示例中,我想启动产生其他算法的几种算法。在将算法封装在某种上下文中之前,该上下文绑定了在该上下文中分配的所有算法并将它们添加到此上下文的列表中。在某个时间可能发生某人想要终止所有算法的情况,可以调用Terminate()方法,该方法在该上下文中对所有算法调用Termimnate()方法。当然,要使这项工作有效,算法需要了解AlgorithmContext结构。

另一个问题是如何将AlgorithmContext传输到下一个线程或任务?它还需要是线程安全的。

在此示例中,您可以争辩说我可以将CancellationToken移交给算法层次结构,但是请记住,这只是一个示例。如果是按照ExecutionContext的方向思考,但也许有更好的方法?

public class Algorithm
{
    public readonly AlgorithmContext Context;
    public Algorithm()
    {
        Context = AlgorithmContext.Current;
    }

    public void Terminate() { }
}

public class SmoothImage : Algorithm { }
public class SharpenImage : Algorithm { }

public class Example
{
    public void Process(float[] imagedata)
    {
        // Everyone below should see the AlgorithmContext.Current until the end of the using.
        // No one shall be able to interfere the Current inside the braces for example if another
        // thread creates another instance of AlgorithmContext.
        var Task1 = Task.Run(() =>
        {
            // The AlgorithmContext.Current shall be Context 1 until the end of the using braces.
            using (var ctx = new AlgorithmContext("Context 1"))
            {
                CancellationTokenSource ct = new CancellationTokenSource();
                ct.Token.Register(() => ctx.Terminate());

                SmoothImage smoothImage = new SmoothImage();
                SharpenImage sharpenImage = new SharpenImage();
            }
        });


        var Task2 = Task.Run(() =>
        {
            // The AlgorithmContext.Current shall be Context 2 until the end of the using braces.
            using (var ctx = new AlgorithmContext("Context 2"))
            {
                CancellationTokenSource ct = new CancellationTokenSource();
                ct.Token.Register(() => ctx.Terminate());

                SmoothImage smoothImage = new SmoothImage();
                SharpenImage sharpenImage = new SharpenImage();
            }
        });

        var Task3 = Task.Run(() =>
        {
            // The AlgorithmContext.Current shall be Context 2 until the end of the using braces.
            using (var ctx = new AlgorithmContext("Context 3"))
            {
                var Task4 = Task.Run(() =>
                    {
                        // The AlgorithmContext.Current shall be Context 3 
                        CancellationTokenSource ct = new CancellationTokenSource();
                        ct.Token.Register(() => ctx.Terminate());

                        SmoothImage smoothImage = new SmoothImage();
                        SharpenImage sharpenImage = new SharpenImage();
                    });
            }
        });


        // There is no current context outside here at all times.
        Task.WaitAll(Task1, Task2, Task3);
    }
}

public class AlgorithmContext : IDisposable
{
    List<Algorithm> Algorithms = new List<Algorithm>();
    public readonly string Name;

    [ThreadStatic]
    public static AlgorithmContext Current;

    public AlgorithmContext(string name)
    {
        Name = name;
        Current = this;
    }

    public void Add(Algorithm algorithm) { Algorithms.Add(algorithm); }

    public void Terminate()
    {
        foreach (var algo in Algorithms) algo.Terminate();
        Algorithms.Clear();
    }

    public void Dispose()
    {
        Current = null;
    }
}

1 个答案:

答案 0 :(得分:1)

我想这没有您描述的那么复杂。 您需要多种算法的上下文。这种情况下的主要工作之一是处理算法的终止。 因此,您需要事件!我重写了整个示例代码。

public abstract class Algorithm
{
    protected readonly AlgorithmContext _context;

    public Algorithm(AlgorithmContext context)
    {
        _context = context;
        _context.Terminated += (sender, e) =>
        {

            Terminate();
        };

    }

    public abstract void Terminate();
}

public class SmoothImage : Algorithm
{
    public SmoothImage(AlgorithmContext context) : base(context)
    {
    }

    public override void Terminate()
    {
        // do whatever you want
    }
}

public class SharpenImage : Algorithm
{
    public SharpenImage(AlgorithmContext context) : base(context)
    {
    }

    public override void Terminate()
    {
        // do whatever you want
    }
}

public class Example
{
    public void Process(float[] imagedata)
    {
        var Task1 = Task.Run(() =>
        {
            using (var ctx = new AlgorithmContext("Context 1"))
            {
                SmoothImage smoothImage = new SmoothImage(ctx);
                SharpenImage sharpenImage = new SharpenImage(ctx);
            }
        });

        // ...
        Task.WaitAll(Task1, Task2, Task3);
    }
}

public class AlgorithmContext : IDisposable
{
    public AlgorithmContext(string name)
    {
        Name = name;
    }

    public event EventHandler Terminated;
    public string Name { get; }

    public void Dispose()
    {
        Terminate();
    }

    public void Terminate()
    {
        Terminated?.Invoke(this, EventArgs.Empty);
    }
}

正如您所说,由于算法彼此之间不了解,因此也许它们不需要处于上下文中。

如果您需要终止上下文中的所有其他算法,那么只需在算法中的某个地方调用_context.Terminate()

无论如何,希望对您有所帮助