非静态方法

时间:2018-02-22 02:13:23

标签: c# json http asynchronous uwp

我正在创建一个UWP应用程序,简单地说我有一个异步void GetWeather函数,它从API读取JSON并创建一个对象。调用Forecast.getWeather()函数我得到错误“非静态方法所需的对象引用”。我已经完成了我的研究,但是还没有找到一个解决方案,因为我不想返回一个对象。如果这是不可能的(也许是一个更好的主意),我将如何返回对象,以便它可以在整个应用程序的许多不同页面上使用,或者如果在void方法中创建,对象值是否仍然可访问?

Forecast.cs

    class Forecast
{
    public async void GetWeather()
    {
        var uri = new Uri("MY API URI HERE");
        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage response = await client.GetAsync(uri))
            {
                using (IHttpContent content = response.Content)
                {
                     var json = await content.ReadAsStringAsync();

                    var result = JsonConvert.DeserializeObject<RootObject>(json);
                    Debug.WriteLine("In async method");
                }
            }
        }
    }
}

的MainPage

 public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        Forecast.GetWeather();

    }
}

Weather.cs

namespace WeatherForecast
{

public class Main
{
    public double temp { get; set; }
    public double temp_min { get; set; }
    public double temp_max { get; set; }
    public double pressure { get; set; }
    public double sea_level { get; set; }
    public double grnd_level { get; set; }
    public int humidity { get; set; }
    public double temp_kf { get; set; }
}

public class Weather
{
    public int id { get; set; }
    public string main { get; set; }
    public string description { get; set; }
    public string icon { get; set; }
}

public class Clouds
{
    public int all { get; set; }
}

public class Wind
{
    public double speed { get; set; }
    public double deg { get; set; }
}

public class Snow
{
    public double __invalid_name__3h { get; set; }
}

public class Sys
{
    public string pod { get; set; }
}

public class List
{
    public int dt { get; set; }
    public Main main { get; set; }
    public List<Weather> weather { get; set; }
    public Clouds clouds { get; set; }
    public Wind wind { get; set; }
    public Snow snow { get; set; }
    public Sys sys { get; set; }
    public string dt_txt { get; set; }
}

public class Coord
{
    public double lat { get; set; }
    public double lon { get; set; }
}

public class City
{
    public int id { get; set; }
    public string name { get; set; }
    public Coord coord { get; set; }
    public string country { get; set; }
}

public class RootObject
{
    public string cod { get; set; }
    public double message { get; set; }
    public int cnt { get; set; }
    public List<List> list { get; set; }
    public City city { get; set; }
}
}

1 个答案:

答案 0 :(得分:2)

问题是您的方法不是静态的,因此您需要创建Forecast类的实例来访问它。您可以在此SO questionhere中详细了解相关内容。

快速解决方案还可以使您的Forecast类保持静态(只要您不想拥有多个不同的实例):

static class Forecast
{
    public static async void GetWeather()
    {
        var uri = new Uri("MY API URI HERE");
        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage response = await client.GetAsync(uri))
            {
                using (IHttpContent content = response.Content)
                {
                     var json = await content.ReadAsStringAsync();

                    var result = JsonConvert.DeserializeObject<RootObject>(json);
                    Debug.WriteLine("In async method");
                }
            }
        }
    }
}

但现在我们遇到了更大的问题。您的方法为async,且为async void。只有当async void方法被称为 fire-and-forget 时,您才应该这样做。它们启动,但是当它们到达第一个真正的异步调用时,它们将自行执行,如果在方法内部发生了不好的事情(例如异常),在症状开始出现之前你永远不会知道它在其他地方以难以调试的方式。此外,您永远不知道result何时实际可供您使用。

最佳解决方案是Task返回类型。这提供了一个 promise ,结果将在方法执行完成时可用。

static class Forecast
{
    public static RootObject Result {get; private set;}

    public static async Task GetWeatherAsync()
    {
        var uri = new Uri("MY API URI HERE");
        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage response = await client.GetAsync(uri))
            {
                using (IHttpContent content = response.Content)
                {
                    var json = await content.ReadAsStringAsync();

                    Result = JsonConvert.DeserializeObject<RootObject>(json);

                    Debug.WriteLine("In async method");
                }
            }
        }
    }
}

您可以看到该方法不再是void,但它仍然不会直接返回RootObject(按照您的要求,否则您可以使用Task<RootObject>返回它)。我还添加了一个Result属性,以便在执行完成后可以访问结果。由于该类为static,因此可在GetWeatherAsync方法调用完成后从任何位置访问该属性。

现在你怎么用这个?您可以在OnNavigatedTo handler:

中调用该方法,而不是构造函数
public override async void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo( e );
    try
    {
       await Forecast.GetWeatherAsync();
       //after await finishes, Result is ready

       //do something with Forecast.Result
    }
    catch
    {
       //handle any exceptions
    }
}

您可能会注意到我违反了async方法不应该void的规则。但是,在这种情况下,我们正在处理具有固定表示法的事件处理程序,因此您没有其他选择。但是,我添加了一个try-catch块,以便我们可以处理任何异常。

我建议您在documentationasync-await上阅读更多内容,因为它可以帮助您更好地理解这个概念。我还建议您查看有关实例与静态的更详细信息,以便更好地理解这些区别以及何时使用它们。