怎么做整个功能不只是一半?

时间:2013-04-20 15:27:57

标签: c# asynchronous microsoft-metro async-await

我目前正在为Windows Store编写C#应用程序。

我有Cache类,News UserControl类和MainPage类

我正在调用MainPage构造函数Cache类,然后调用InitializeData for News类,其中我使用来自Cache的数据,但是有问题,在Cache构造函数中我接收数据但是他没有做整个函数,他从Cache构造函数切换到第三个的InitializeData等待函数。

的MainPage:

public MainPage()
{
    this.InitializeComponent();

    Cache.Cache cache = new Cache.Cache();
    NewsContent.InitializeData(cache.MyData);
}

高速缓存:

    public Cache()
    {
        Initialization = Init();
    }

    public Task Initialization
    {
        get;
        private set;
    }

    private async Task Init()
    {
        try
        {
            cS        = await folder.CreateFileAsync("cache.txt", CreationCollisionOption.OpenIfExists);
            cS_titles = await folder.CreateFileAsync("titles_cache.txt", CreationCollisionOption.OpenIfExists);

            string contentOfFile = await FileIO.ReadTextAsync(cS);
            int contentLength = contentOfFile.Length;

            if (contentLength == 0) // download data for first using
            {
                await debug.Write("Is empty!");

                //.......
                // ....

                await FileIO.AppendTextAsync(cS, file_content);
                await FileIO.AppendTextAsync(cS_titles, file_content_titles);
            }
            else // check for same data, if isnt same download new, else nothing
            {
                await debug.Write(String.Format("Isnt empty. Is long: {0}", contentLength)); // here he break and continue to NewsContent.InitializeData(cache.MyData);

                // ....
                // ....
            }

            await MyFunction(); // i need get constructor to this point then he will do NewsContent.InitializeData(cache.MyData);
        }
        catch (Exception)
        {

        }
    }

这可能吗?对于任何想法,谢谢!

2 个答案:

答案 0 :(得分:2)

当您调用异步方法并且从不等待它完成时,会发生这种情况。

异步方法的重点是你阻止...而你的构造函数本身不能是异步的。

一种选择是编写异步静态方法来创建缓存:

static async Task<Cache> CreateCache()
{
    // Change your InitializeData to return the data which the cache needs
    var data = await InitializeData();
    return new Cache(data);
}

从根本上说,你仍然需要任何调用CreateCache来理解它是异步发生的。您不希望阻止UI线程等待全部初始化。

编辑:我没有发现这是从MainPage构造函数调用的。您可能会再次应用相同的方法:

public static async Task<MainPage> CreateMainPage()
{
    var cache = await Cache.CreateCache();
    return new MainPage(cache);
}

这假设您确实无法在没有完全初始化缓存的情况下创建主页面。如果可以处理(例如显示“Loading ...”状态,直到它完成初始化),那就更好了。

答案 1 :(得分:2)

Stephen Cleary's article on async and constructors介绍了如何使其发挥作用。

在您的情况下,我认为工厂模式(如Jon的回答中所建议的)不适用于MainPage,因为它是一个GUI组件。但第二种方法,即异步初始化模式,将起作用。

您已经为Cache实施了该模式,现在您还需要为MainPage实施该模式:

public MainPage()
{
    Initialization = InitializeAsync();
}

public Task Initialization { get; private set; }

private async Task InitializeAsync()
{
    Cache.Cache cache = new Cache.Cache();
    await cache.Initialization;
    NewsContent.InitializeData(cache.MyData);        
}

如果MainPage有一些事件依赖于初始化完成,那么您可以在async处添加await this.Initialization并在其开头添加MainPage。此外,您可能希望在InitializeAsync()的{​​{1}}末尾启用此类按钮或类似内容。