首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >可以将回调调用转换为IEnumerable

可以将回调调用转换为IEnumerable
EN

Stack Overflow用户
提问于 2011-02-10 18:01:24
回答 5查看 1.1K关注 0票数 8

我正在编写一个围绕第三方库的包装器,它有一个扫描它管理的数据的方法。该方法接受一个回调方法,它为找到的数据中的每一项调用该回调方法。

例如,方法本质上是:void Scan(Action<object> callback);

我想包装它并公开一个像IEnumerable<object> Scan();这样的方法

如果没有单独的线程来执行实际的扫描和缓冲区,这是可能的吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-02-10 19:02:36

您可以非常简单地使用Reactive来完成此操作:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        foreach (var x in CallBackToEnumerable<int>(Scan))
            Console.WriteLine(x);
    }

    static IEnumerable<T> CallBackToEnumerable<T>(Action<Action<T>> functionReceivingCallback)
    {
        return Observable.Create<T>(o =>
        {
            // Schedule this onto another thread, otherwise it will block:
            Scheduler.Later.Schedule(() =>
            {
                functionReceivingCallback(o.OnNext);
                o.OnCompleted();
            });

            return () => { };
        }).ToEnumerable();
    }

    public static void Scan(Action<int> act)
    {
        for (int i = 0; i < 100; i++)
        {
            // Delay to prove this is working asynchronously.
            Thread.Sleep(100);
            act(i);
        }
    }
}

请记住,这不会处理取消之类的事情,因为回调方法实际上并不允许这样做。一个适当的解决方案需要在外部库部分进行工作。

票数 5
EN

Stack Overflow用户

发布于 2011-02-10 18:10:21

您应该调查Rx project -这允许将事件源作为IEnumerable使用。

我不确定它是否允许普通的回调以这种方式表示(它针对的是.NET事件),但它值得一看,因为它应该可以将常规的回调表示为IObservable

票数 4
EN

Stack Overflow用户

发布于 2011-02-10 19:15:55

下面是一个阻塞枚举器( Scan方法需要在单独的线程中运行)

代码语言:javascript
复制
    public class MyEnumerator : IEnumerator<object>
    {
        private readonly Queue<object> _queue = new Queue<object>();
        private ManualResetEvent _event = new ManualResetEvent(false);

        public void Callback(object value)
        {
            lock (_queue)
            {
                _queue.Enqueue(value);
                _event.Set();
            }
        }

        public void Dispose()
        {

        }

        public bool MoveNext()
        {
            _event.WaitOne();
            lock (_queue)
            {
                Current = _queue.Dequeue();
                if (_queue.Count == 0)
                    _event.Reset();
            }
            return true;
        }

        public void Reset()
        {
            _queue.Clear();
        }

        public object Current { get; private set; }

        object IEnumerator.Current
        {
            get { return Current; }
        }
    }

    static void Main(string[] args)
    {
        var enumerator = new MyEnumerator();
        Scan(enumerator.Callback);

        while (enumerator.MoveNext())
        {
            Console.WriteLine(enumerator.Current);
        }
    }

您可以将其封装在一个简单的IEnumerable<Object>中,但我不建议您这样做。IEnumerable列表意味着您可以在同一列表上运行多个枚举器,这在本例中是不能的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4955607

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档