代码之家  ›  专栏  ›  技术社区  ›  arynaq

泛型类型的类型擦除,是动态

  •  1
  • arynaq  · 技术社区  · 7 年前

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

    我知道我可以用 ThreadPool Task.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; }
        }
    

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

    2 回复  |  直到 7 年前
        1
  •  4
  •   Nkosi    7 年前

    另一种不涉及保持委托或任务完成源的方法是通过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 委托是为了处理所需的行为而创建的,并在需要时提供给要调用的包装器。

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

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

        2
  •  2
  •   Damien_The_Unbeliever    7 年前

    我想移动一些功能 TaskWrapper 定义一个从中派生的通用实现非常有意义:

    private class TaskWrapper
    {
        private readonly Action _function;
        private readeonly TaskCompletionSource<bool> _cts;
        public TaskWrapper (Action function, TaskCompletionSource<bool> cts) {
           _function = function;
           _cts = cts;
        }
        protected TaskWrapper () {
           _function = null;
           _cts = null;
        }
        public virtual void DoWork() {
           _function();
           cts.SetResult(true);
        }
    }
    private class TaskWrapper<T> : TaskWrapper {
        private readonly Func<T> _function;
        private readeonly TaskCompletionSource<T> _cts;
        public TaskWrapper (Func<T> function, TaskCompletionSource<T> cts) : base() {
           _function = function;
           _cts = cts;
        }
        public override void DoWork(){
           _cts.SetResult(_function());
        }
    }
    

    DoWork 而不知道泛型是否是在构建过程中使用的。


    我还注意到,您当前的实现应该会让您感到更不舒服。它没有成功 Function 对于 Action 项目。