c# - 通用类型的类型删除,更好地替代动态

标签 c# generics dynamic

我正在尝试创建一个可以将任何 Func<T> 作为输入的工作池或 Action ,返回一个 Task 并在未来某个时间在某个线程中安排该任务的结果。

我知道我可以使用 ThreadPoolTask.Factory但我这样做是为了学习。

现在我下面的实现依赖于我能够排队 TaskCompletionSource<T>通过将其包裹在 dynamic 中里面TaskWrapper .我不太愿意这样做(因为我可以想象这具有不可忽略的运行时成本)但我不知道有任何替代方案。

public class WorkerHub
{
    private readonly ConcurrentQueue<TaskWrapper> _tasks;
    private readonly Timer _timer;

    public WorkerHub()
    {
        _timer = new Timer();
        _tasks = new ConcurrentQueue<TaskWrapper>();
    }

    public Task<TResult> Post<TResult>(Func<TResult> func)
    {
        var cts = new TaskCompletionSource<TResult>();
        var wrapper = new TaskWrapper {CompletionSource = cts, Function = func};
        _tasks.Enqueue(wrapper);
        return cts.Task;
    }

    public Task Post(Action action)
    {
        var cts = new TaskCompletionSource<bool>();
        var wrapper = new TaskWrapper {CompletionSource = cts, Function = action, isVoid = true};
        _tasks.Enqueue(wrapper);
        return cts.Task;
    }

    private TaskWrapper Pop()
    {
        _tasks.TryDequeue(out var wrapper);
        return wrapper;
    }


    public void Start()
    {
        _timer.Enabled = true;
        _timer.AutoReset = true;

        _timer.Interval = 2500;
        _timer.Elapsed += (sender, args) =>
        {
            var wrapper = Pop();
            if (wrapper != null) wrapper.CompletionSource.SetResult(wrapper.isVoid ? true : wrapper.Function());
        };
        _timer.Start();
    }

    public void Stop()
    {
    }

    private class TaskWrapper
    {
        public bool isVoid { get; set; }
        public dynamic Function { get; set; }
        public dynamic CompletionSource { get; set; }
    }

能够绑定(bind)到同一集合中不同类型的完成源和不同类型的输入函数的“正确”方法是什么?

最佳答案

另一种不涉及保留委托(delegate)或任务完成源的方法是通过 lambda 表达式

public class WorkerHub {
    private readonly ConcurrentQueue<TaskWrapper> _tasks;
    private readonly Timer _timer;

    public WorkerHub() {
        _timer = new Timer();
        _tasks = new ConcurrentQueue<TaskWrapper>();
    }

    public Task<TResult> Post<TResult>(Func<TResult> func) {
        var cts = new TaskCompletionSource<TResult>();

        Action handler = () => {
            cts.SetResult(func());
        };

        var wrapper = new TaskWrapper { Invoke = handler };
        _tasks.Enqueue(wrapper);
        return cts.Task;
    }

    public Task Post(Action action) {
        var cts = new TaskCompletionSource<bool>();
        Action handler = () => {
            action();
            cts.SetResult(true);
        };
        var wrapper = new TaskWrapper { Invoke = handler };
        _tasks.Enqueue(wrapper);
        return cts.Task;
    }

    private TaskWrapper Pop()
    {
        _tasks.TryDequeue(out var wrapper);
        return wrapper;
    }


    public void Start() {
        _timer.Enabled = true;
        _timer.AutoReset = true;

        _timer.Interval = 2500;
        _timer.Elapsed += (sender, args) => {
            var wrapper = Pop();
            if (wrapper != null)
                wrapper.Invoke();
        };
        _timer.Start();
    }

    public void Stop() {
    }

    private class TaskWrapper {
        public Action Invoke { get; set; }
    }
}

创建一个 Action 委托(delegate)来处理所需的行为,并将其提供给包装器以在需要时调用。

包装器现在变得多余,可以完全删除

public class WorkerHub {
    private readonly ConcurrentQueue<Action> _tasks;
    private readonly Timer _timer;

    public WorkerHub() {
        _timer = new Timer();
        _tasks = new ConcurrentQueue<Action>();
    }

    public Task<TResult> Post<TResult>(Func<TResult> func) {
        var cts = new TaskCompletionSource<TResult>();
        Action handler = () => {
            cts.SetResult(func());
        };
        _tasks.Enqueue(handler);
        return cts.Task;
    }

    public Task Post(Action action) {
        var cts = new TaskCompletionSource<bool>();
        Action handler = () => {
            action();
            cts.SetResult(true);
        };
        _tasks.Enqueue(handler);
        return cts.Task;
    }

    public void Start() {
        _timer.Enabled = true;
        _timer.AutoReset = true;

        _timer.Interval = 2500;
        _timer.Elapsed += (sender, args) => {
            Action handler = null;
            if (_tasks.TryDequeue(out  handler) && handler != null)
                handler.Invoke();
        };
        _timer.Start();
    }

    public void Stop() {
    }
}

是的,可以进行更多的重构来改进这个设计,但这应该足以让总体思路得到理解

关于c# - 通用类型的类型删除,更好地替代动态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52647505/

相关文章:

c# - RDLC 和 asp.net mvc 中的深入报告

java - ArrayList<Integer> 是否允许添加字符串?

ios - 在iOS中实现动态uitableViewCell的最佳方法

java - 为什么 new HashMap<> 在 JDK 1.6 而不是 1.7 中产生错误

PHP 反射类 hasMethod 和 __call()

javascript - javascript 和 css 中的图像上的文字

c# - 异常未在 Async/Await block 中捕获

c# - HttpListener 在 Mono 上运行良好吗?

c# - 成员名称不能与其在 g.cs 文件中的封闭类型相同

c# - 如何递归地将 IEnumerable<T> 转换为字符串?