如何从异步方法返回一个对象(c# - xamarin.forms)?

时间:2017-03-14 14:36:19

标签: c# asynchronous xamarin xamarin.forms async-await

在Xamarin.Forms应用程序中,我使用GeoLocator来检索有关我的位置的信息。 该方法是异步的。我必须返回包含位置参数的对象,但我不能。

这是我的类PositionPage

的构造函数
public PositionPage()
{           
    getCurrentPosition();

    var map = new Map(
    MapSpan.FromCenterAndRadius(
        new Position(45.987487, 9.366337), Distance.FromMiles(0.3)))
        {
            IsShowingUser = true,
            HeightRequest = 100,
            WidthRequest = 960,
            VerticalOptions = LayoutOptions.FillAndExpand
        };
    var stack = new StackLayout { Spacing = 0 };
    stack.Children.Add(map);
    Content = stack;            
}

这是异步方法(现在是一个void方法):

public async void getCurrentPosition() 
{
    try
    {
        var locator = CrossGeolocator.Current;
        locator.DesiredAccuracy = 50;

        var position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);

        Debug.WriteLine("Position Status: {0}", position.Timestamp);
        Debug.WriteLine("Position Latitude: {0}", position.Latitude);
        Debug.WriteLine("Position Longitude: {0}", position.Longitude);                
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
    }
}

当我调用getCurrentPosition()在MapSpan中传递它时,我需要返回一个位置对象。

我该怎么做?

4 个答案:

答案 0 :(得分:7)

其他答案似乎都没有解决您的代码的主要问题,因此我将添加我的答案。

您有一个异步方法getCurrentPosition()。此方法等待呼叫:locator.GetPositionAsync(timeoutMilliseconds: 10000)。此代码唯一的问题是您没有返回从locator.GetPositionAsync()获得的结果。您可以通过执行以下操作来解决此问题:

//SomeType needs to be the same type that locator.GetPositionAsync() returns
//Also C# naming conventions say that any async methods should end with "Async", 
//obviously not required but it will make your life easier later
public async Task<SomeType> GetCurrentPositionAsync() 
{
    SomeType position = null;
    try
    {
        var locator = CrossGeolocator.Current;
        locator.DesiredAccuracy = 50;

        position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);
        Debug.WriteLine("Position Status: {0}", position.Timestamp);
        Debug.WriteLine("Position Latitude: {0}", position.Latitude);
        Debug.WriteLine("Position Longitude: {0}", position.Longitude);            
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
    }
    return position;
}

你遇到的最大问题是你的构造函数正在尝试调用async方法,该方法将是一个同步调用,它基本上否定了async / await的好处。

强烈建议更改此应用程序的设计,以便您利用async / await。它不一定是一个重大变化。您可以实现构造对象并为您返回的静态异步方法,这样您就可以等待该调用。像这样:

public class PositionPage
{
    public static async Task<PositionPage> CreateAsync()
    {
        var position = await GetCurrentPositionAsync();

        var map = new Map(
            MapSpan.FromCenterAndRadius(
                new Position(45.452481, 9.166337),
                Distance.FromMiles(0.3)))
        {
            IsShowingUser = true,
            HeightRequest = 100,
            WidthRequest = 960,
            VerticalOptions = LayoutOptions.FillAndExpand
        };
        var stack = new StackLayout { Spacing = 0 };
        stack.Children.Add(map);


        var positionPage= new PositionPage();
        positionPage.Content = stack;
        return positionPage;
    }

    private PositionPage()
    {

    }

    //SomeType needs to be the same type that locator.GetPositionAsync() returns
    //Also C# naming conventions say that any async methods should end with "Async", obviously not required but it will make your life easier later
    public async Task<SomeType> GetCurrentPositionAsync() 
    {
        try
        {
            var locator = CrossGeolocator.Current;
            locator.DesiredAccuracy = 50;

            var position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);
            Debug.WriteLine("Position Status: {0}", position.Timestamp);
            Debug.WriteLine("Position Latitude: {0}", position.Latitude);
            Debug.WriteLine("Position Longitude: {0}", position.Longitude);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
        }
    }
}

答案 1 :(得分:2)

您需要从Task<T>方法返回async,不要让它返回void,您需要重构方法,如:

public async Task<Geoposition> getCurrentPosition() 
{
  Geoposition position = null;
  try
  {
     var locator = CrossGeolocator.Current;
     locator.DesiredAccuracy = 50;

     position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);

     Debug.WriteLine("Position Status: {0}", position.Timestamp);
     Debug.WriteLine("Position Latitude: {0}", position.Latitude);
     Debug.WriteLine("Position Longitude: {0}", position.Longitude);

  }
  catch (Exception ex)
  {
     Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
  }

  return position;

}

并且在调用方面你还需要为理想场景制作该方法async,但是如果你想同步调用异步方法,那么在调用方面它就像:

var position = getCurrentPosition().Result;
// please note that it will be blocking call
// it is synchronously calling the async method

我不知道GetLocationAsync的返回类型是什么,但它会返回Task<T>,其中T将是某种特定类型,因此更好的是设置返回类型Task<Geoposition>的方法,假设它返回Task<Geoposition>,但您可以将其替换为GetPositionAsync方法的返回类型。

或者您可能希望保持getCurrentPosition同步,可以这样做:

public Geoposition getCurrentPosition() 
{
  Geoposition position = null;
  try
  {
     var locator = CrossGeolocator.Current;
     locator.DesiredAccuracy = 50;

     position = locator.GetPositionAsync(timeoutMilliseconds: 10000).Result;

     Debug.WriteLine("Position Status: {0}", position.Timestamp);
     Debug.WriteLine("Position Latitude: {0}", position.Latitude);
     Debug.WriteLine("Position Longitude: {0}", position.Longitude);

  }
  catch (Exception ex)
  {
     Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
  }

  return position;

}

希望它有所帮助!

答案 2 :(得分:1)

GetPositionAsync返回Task<Position>

我认为你应该使用

public async Task<Position> getCurrentPosition() {

        Position position = null;

        try
        {
            var locator = CrossGeolocator.Current;
            locator.DesiredAccuracy = 50;

            position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);

            Debug.WriteLine("Position Status: {0}", position.Timestamp);
            Debug.WriteLine("Position Latitude: {0}", position.Latitude);
            Debug.WriteLine("Position Longitude: {0}", position.Longitude);

        }
        catch (Exception ex)
        {
            Debug.WriteLine("Unable to get location, may need to increase timeout: " + ex);
        }

        return position;
    }

答案 3 :(得分:-2)

GetCurrentPosition现在有一个返回类型为void,所以如果你想返回某个类型的值,你应该定义返回类型。因为它也是一个异步函数,GetCurrentPosition的返回类型应该是这样的任务:

public async Task<Position> getCurrentPosition() { 
  var position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);
  return position;
}

此外,调用函数应该使用等待:

Public PositionPage() {
    Position position = await getCurrentPosition();
}