我正在尝试在我正在创建的Windows Phone 8.1 API中实现一个简单的缓存机制。我在visual studio中选择了Windows Phone可移植类库模板。
缓存类看起来像这样,
[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)
请你指点我正确的方向吗?我的诊断是对的吗?有没有更好的方法呢?任何指针都很受欢迎。
谢谢!
答案 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
在调用之间编组同步上下文的方式有关。