在Windows Phone 8.1类库中实现简单缓存

时间:2014-12-26 12:27:12

标签: c# windows-phone-8.1 async-await portable-class-library

我正在尝试在我正在创建的Windows Phone 8.1 API中实现一个简单的缓存机制。我在visual studio中选择了Windows Phone可移植类库模板。

参考:http://channel9.msdn.com/Series/Windows-Phone-8-1-Development-for-Absolute-Beginners/Part-22-Storing-and-Retrieving-Serialized-Data

缓存类看起来像这样,

[DataContract]
class cache
{
    private const string JSONFILENAME = "data.json";

    [DataMember]
    Dictionary<Int32, item> cDictionary;

    [DataMember]
    int _maxSize;

    public int MaxSize
    {
      get { return _maxSize; }
      set { _maxSize = value; }
    }
    public cache(int maxSize){
        cDictionary = new Dictionary<int, item>();
        _maxSize = maxSize;
    }
    public void push(Int32 id, item obj)
    {
        if (!cDictionary.ContainsKey(id)) {
            cDictionary.Add(id, obj);
        }            
    }

    internal static async Task<cache> Load()
    {
        cache obj = null;
        try
        {
            var jsonSerializer = new DataContractJsonSerializer(typeof(cache));

            using (var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(JSONFILENAME))
            {
                obj = (cache)jsonSerializer.ReadObject(myStream);
            }
        }
        catch (FileNotFoundException)
        {
            obj = null;
        }

        return obj;
    }

    internal static async void Save(cache obj)
    {
        var serializer = new DataContractJsonSerializer(typeof(cache));
        using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(
                      JSONFILENAME,
                      CreationCollisionOption.ReplaceExisting))
        {
            serializer.WriteObject(stream, obj);
        }
    }}

对象进入字典的item类看起来像这样,

[DataContract]
class item
{
    [DataMember]
    string _fName;

    public string FName
    {
        get { return _fName; }
        set { _fName = value; }
    }
    [DataMember]
    string _lName;

    public string LName
    {
        get { return _lName; }
        set { _lName = value; }
    }
    [DataMember]
    int _id;

    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    public item(int id, string fName, string lName)
    {
        this.Id = id;
        this.FName = fName;
        this.LName = lName;
    }
}

想法是:最终用户创建api的实例并调用方法doSomething()。该方法首先查找缓存(示例中未显示),如果找到,则返回Item对象,否则,从Web服务(未显示)获取项目对象,然后将其推送到缓存。

public class api
{
    cache tCache;
    string apiKey;

    public laas(string apiKey)
    {
        this.apiKey = apiKey;
        this.tCache = new cache(100);
    }

    public async void Initialize(api obj)
    {
        //If cache exists
        obj.tCache = await cache.Load();
        if (obj.tCache == null)
        {
            obj.tCache = new cache(100);
        }
    }

    public void doSomething(string id)
    {            
        tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx"));
        cache.Save(tCache);
    }
}

我想在api类的构造函数中初始化/加载缓存,但由于ApplicationData.Current.LocalFolder仅提供从持久存储读取和写入数据的异步方法,因此我创建了一个单独的静态异步类Initiialize()会加载缓存,因为制作异步构造函数毫无意义。

问题:声明 tCache.push(id.GetHashCode(),新项目(1,&#34; xxxx&#34;,&#34; xxx&#34;) );; 在doSomething()中抛出 null引用异常。这可能会发生,因为由于异步操作,tCache还没有被加载/初始化。

我曾尝试 obj.tCache = await cache.Load()。结果等待加载完成,但是挂起了我的应用程序。 (http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

请你指点我正确的方向吗?我的诊断是对的吗?有没有更好的方法呢?任何指针都很受欢迎。

谢谢!

1 个答案:

答案 0 :(得分:1)

可能发生的事情是您正在调用Initialize但未等待它,因为它是async void

您需要做的是改变:

public async void Initialize(api obj)

要:

public async Task Initialize(api obj)

然后,您需要await Initialize(obj),这将确保缓存在使用前完成。

请注意,async void仅适用于顶级事件处理程序,否则不应使用。 此外,Task.Result挂起您的应用程序的原因是因为它导致死锁,这与async在调用之间编组同步上下文的方式有关。