【问题标题】:how can i pass the result of the asynchronous contact search back to the calling method?如何将异步联系人搜索的结果传递回调用方法?
【发布时间】:2011-10-29 10:27:29
【问题描述】:

我正在尝试编写一个获取联系人并将其转换为数据对象并返回的方法。我了解由于联系人搜索是异步的,因此调用方法也需要;但是,我想返回一个对象作为调用搜索的父方法的一部分,我不太确定最好的方法是什么。

我目前得到的伪代码是:

public Person GetRandomPerson(string s)
{
    Person myPerson = new Person();

    Person contacts = new Contacts();            

    contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
    contacts.SearchAsync(String.Empty, FilterKind.None, "All Contacts");            

    return Person;    //I'm not sure how this will ever work...
}

void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
    //convert a Contact object to Person object here
}

我已经在这个地方做了一些阅读 (like this SO question),但我不太确定嵌套异步返回调用的外观,或者我如何从基于事件的异步联系中传递结果重新搜索父调用方法 - 我将如何实现这种效果?

【问题讨论】:

    标签: c# asynchronous contacts windows-phone-7.1


    【解决方案1】:

    我稍微更改了您的代码。你需要一个在GetRandomPersoncontacts_SearchCompleted 之间的共享类Person。看看contacts.SearchAsync的参数,也许你可以不声明为class的私有字段,而将myPerson传递给它。

    Person myPerson = new Person(); //*****
    public Person GetRandomPerson(string s)
    {
        Person contacts = new Contacts();            
    
        contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
        contacts.SearchAsync(String.Empty, FilterKind.None, "All Contacts");            
    
        wait.WaitOne();      //*****
        return myPerson;    //I'm not sure how this will ever work...
    }
    
    ManualResetEvent wait = new ManualResetEvent(false); //*****
    
    void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
        //Fill myPerson
        wait.Set(); //*****
    }
    

    【讨论】:

    • 虽然这有点像单例 - 所以如果你快速连续调用 GetRandomPerson 两次,有(无论多么小)你会得到第二个 Person 的结果两次的机会.. .
    • 虽然我可以将 Person 对象作为第三个参数传递...嗯。
    • 另外,这不起作用,与此处列出的类似问题 - stackoverflow.com/questions/7701690/… 我怀疑 wait.one 会暂停线程并且永远不会返回到 contacts_SearchCompleted 以“设置”等待...我可以尝试将 contacts.SearchAsync 推送到另一个线程,也许...
    • @Blakomen,我想你自己找到了解决方案。
    • 不,我只是说它不适用于 waitone() 会导致问题并意味着搜索永远不会完成 - 看看将部分或全部部分推入另一个线程是否会有所帮助。跨度>
    【解决方案2】:

    好吧,我终于解决了,解决方案分为两部分:

    1) 将我想要从联系人搜索结果中创建的 DataObject 作为 .SearchAsync 方法调用中的第三个对象状态参数传递。

    2) 将对 GetRandomPerson 的调用(最初只是关闭 Button_Click)移动到后台线程;在这种情况下,我使用了 ThreadPool.QueueUserWorkItem。 UI 线程似乎无法从 WaitOne() 中很好地恢复,这是可以理解的。

    如果您有兴趣,工作代码解决方案是:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        //this should be done asynchronously - "request" a person
    
        List<Person> people = new List<Person>();
        PersonService ps = new PersonService();     
        ThreadPool.QueueUserWorkItem(func =>
        {
            for (int i = 0; i < 10; i++)
            {
                        people.Add(ps.GetRandomPerson()); //you need to call this on a separate thread or it will lock the ui thread.                       
            }                                   
            Dispatcher.BeginInvoke(() => { Status.Text = "done"; });    //your button click method is now also asynchronous
        });
    }
    
    /*** Helper class ***/      
    
    public class PersonService
    {
        AutoResetEvent sync = new AutoResetEvent(false);
    
        public Person GetRandomPerson()
        {
            Person person = new Person();
            Contacts contacts = new Contacts();            
            contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);            
            contacts.SearchAsync(String.Empty, FilterKind.None, person);
            sync.WaitOne();
            return person;
        }
    
        void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
        {
            Contact[] allContacts = e.Results.ToArray();
            Contact randomContact = allContacts[new Random().Next(allContacts.Length)];
            Person person = (Person)e.State;
            person.Name = randomContact.DisplayName;
    
            sync.Set();
        }
    }
    

    我仍然很想知道是否有人对此有更优雅的解决方案,所以如果你有的话,请大声说出来!

    【讨论】:

    • 人们(不知道PersonService 的内部情况)直接调用GetRandomPerson 将被阻止。这和我的回答没有太大区别。我认为,在线程中调用GetRandomPerson 应该在PersonService 中处理
    • 我想将后台线程移动到 PersonService 中可能会更好 - 但无论如何我需要将整个调用推送到后台线程以保持 UI 线程运行,所以这就是我为什么保持原样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    相关资源
    最近更新 更多