【问题标题】:How can I wait for await to finish and only then continue?我怎样才能等待 await 完成然后才继续?
【发布时间】:2013-05-10 12:05:48
【问题描述】:

我有两种方法:

private async Task<GeoCoordinate> CenterMapOnMyLocation()
    {
        Geolocator myGeolocator = new Geolocator();
        Geoposition myGeoposition = await myGeolocator.GetGeopositionAsync();          
        Geocoordinate myGeocoordinate = myGeoposition.Coordinate;
        GeoCoordinate myGeoCoordinate =
            ConvertGeocoordinate(myGeocoordinate);

        MapCenter = myGeoCoordinate;
        if (MyLocation.Latitude == 0 && MyLocation.Longitude == 0)
        {
            MyLocation = MapCenter;
        }

        return myGeoCoordinate;
    }

private void GetClosestLocations(GeoCoordinate myLocation)
    {
        var locations = new ObservableCollection<PushPinModel>
                    {
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(51.569593, 10.103504),
                                LocationName = "1"
                            },
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(-45.569593, 1.103504),
                                LocationName = "2"
                            },
                        new PushPinModel
                            {
                                Location = new GeoCoordinate(0, 0),
                                LocationName = "3"
                            }
                    };
        foreach (var location in locations)
        {
            location.DistanceToMyLocation = HaversineDistance(myLocation, location.Location);
        }

        Treks = new ObservableCollection<PushPinModel>(locations.OrderBy(l => l.DistanceToMyLocation).Take(2).ToList());
    }

在构造函数中我有这样的东西:

public NearbyControlViewModel()
    {
        var test = CenterMapOnMyLocation();
        GetClosestLocations(test);
    }

现在,我的问题是,当在构造函数中调用第二个方法时,“test”变量还没有初始化……因为它是异步的。我想要做的是等待它被初始化,然后调用第二种方法。如果我从异步方法调用我的第二个方法,我会得到一个异常: InvalidOperationException - 集合处于不可写模式。 “Treks”值绑定到 MapItemsControl。所以我猜是线程的问题。

【问题讨论】:

  • 看看主题“安全线程”。尤其是看看主题死锁和竞争条件。
  • 你的代码能编译吗? CenterMapOnMyLocation 返回 Task&lt;GeoCoordinate&gt;GetClosestLocations 接受 GeoCoordinate
  • 是的,它确实可以编译。

标签: c# windows-phone-8 mvvm-light async-await


【解决方案1】:

您需要使用异步初始化。我在blog post on async construction 中给出了几种不同的解决方案。

请注意,异步代码强制您拥有更好的 UI 设计。即,您必须为您的 UI 设计某种“在地图居中之前”状态。 UI 最初会在该状态下启动,然后当(异步)初始化完成时,UI 会更新。

【讨论】:

    【解决方案2】:

    如果不是构造函数:

    public async Task SomeMethod()
    {
        var test = await CenterMapOnMyLocation();
        GetClosestLocations(test);
    }
    

    但是 - 使用构造函数?也许只是不要那样做。尝试在构造函数中等待可能是致命的——尤其是在某些同步上下文中——可能会立即死锁。

    考虑在构造函数之后启动它。

    【讨论】:

    • @I4V 啊,没想到是构造函数!确实,在那种情况下:不要那样做 :p
    • 我按照你所说的做了:创建了一个新类“SomeMethod”并在构造函数中调用它,但我又得到了异常。
    • @RaresFelecan 你现在遇到了什么异常? test 指的是什么?它不能是SomeMethod,因为那将是await...但同样:在构造函数中调用任何这个似乎是一个根本坏主意。为什么要从构造函数中调用它?
    • 好的,让我们看看我是否可以更清楚。看看这里:stackoverflow.com/questions/16417978/…。我在 DependencyProperty 的这一行遇到了异常:pushpin.ItemsSource = (IEnumerable)e.NewValue;
    【解决方案3】:

    您可以在调用 GetClosestLocation 之前添加test.Wait();;毕竟,您从 CenterMapOnMyLocation 获得了一个任务。 (编辑:但事实上,Marc 是对的,等待是邪恶的。您可能应该重构以在构造函数之外调用异步代码。)

    【讨论】:

    • 这样做永远不会被等待。
    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 2011-12-14
    • 2016-05-19
    • 2021-01-13
    • 2019-08-16
    • 2012-02-27
    • 2019-05-21
    • 2014-09-25
    相关资源
    最近更新 更多