Task.Run中的实例变量为null

时间:2014-09-04 17:43:54

标签: c# asynchronous task-parallel-library async-await c#-5.0

更新:

public MobileServiceUser CurrentMsUser { get; private set; } 

我有一个实例属性CurrentMsUser,它已填充并且我试图在异步方法中引用它,但由于某种原因它在方法中为null。我在属性setter上设置了一个断点,它永远不会被设置为null,所以我很确定该属性永远不会变为null。异步方法返回后再次出现。似乎只要我在匿名异步方法中,我就无法访问该属性。这是我的方法:

public async Task CreateOrRetrieveAppUserAsync()
{
    await Task.Run (async () => {
        try {
            var usersCollection = await _userTable.ToCollectionAsync ();
            var users = usersCollection.
                Where(x =>
                    x.FacebookToken == CurrentMsUser.UserId).
                ToList();
            if (users.Count == 1) {
                CurrentRwUser = users [0];
            } else {
                CurrentRwUser = new User { 
                    FacebookToken = CurrentMsUser.UserId, 
                    GoogleToken = "test",
                    TwitterToken = "test",
                    MicrosoftToken = "test",
                    Email = "test@gmail.com",
                    FacebookId = App.FacebookProvider.GetCurrentUserId (),
                    Name = App.FacebookProvider.GetCurrentUserName ()
                };
                await InsertUserAsync (CurrentRwUser);
                await SyncAsync();
            }
        } catch (Exception ex) {
            Debug.WriteLine ("CreateOrRetrieveAppUser failed: {0}", ex.Message);
        }
    }).ConfigureAwait(continueOnCapturedContext:false);
}

1 个答案:

答案 0 :(得分:3)

看来该变量是线程本地的,这就是为什么它的值只能在主线程中访问。

在移动到后台线程之前,您应该在主线程中获取该变量的值以避免此问题。

public async Task CreateOrRetrieveAppUserAsync()
{
    var userId = CurrentMsUser.UserId;
    await Task.Run (async () => {
    //...
    //use userId here
    });
}

当然,鉴于您似乎没有任何长时间运行的 CPU绑定工作,并且您在此处的所有工作都已经是基于异步任务的IO工作,您< em>应该能够简单地完全删除Task.Run调用,允许你的小CPU绑定工作必须在UI线程中运行,而不会阻止它到期对于长时间运行的操作,所有操作都已异步。

哦,因为你只需要usersCollection的第一项,你应该使用First,而不是ToList,以避免将整个结果集实现到内存中。您还应该在调用First之前执行ToCollectionAsync和过滤,如果可能的话,通过查询提供程序执行所有这些过滤,而不是将整个集合实现为你的申请。