2014-09-04 2 views
0

UPDATE:переменная экземпляра является пустым внутри Task.Run

public MobileServiceUser CurrentMsUser { get; private set; } 

У меня есть свойство CurrentMsUser экземпляр, который заполняется, и я пытаюсь ссылаться на него в методе асинхронным, но по какой-то причине он является недействительным в метод. Я установил точку останова в настройщике свойств, и она никогда не установлена ​​в значение null, поэтому я уверен, что свойство никогда не станет null. После того, как метод async вернет его, он снова появится. Кажется, как только я нахожусь в анонимном асинхронном методе, я не могу получить доступ к свойству. Вот мой метод:

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 = "[email protected]", 
        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); 
} 
+2

Из любопытства, почему вы завершаете всю эту логику в новой задаче? –

+0

Поскольку метод вызывается из потока пользовательского интерфейса – winnicki

+1

Где * точно * это null? Кажется, это устанавливает значение 'CurrentRwUser', поэтому я бы предположил, что это было null, прежде чем вы вызвали этот метод? Вы говорите, что это все еще null * после * задания? Как вы это определяете? Неверно ли это в 'InsertUserAsync'? Если вы запустили 'Debug.WriteLine (CurrentRwUser.UserId)' в конце этого метода, он выкинул «NullReferenceException»? –

ответ

3

Оказывается, что это переменная нить локальным, поэтому его значение доступно только в основном потоке.

Вы должны получить значение этой переменной в своем основном потоке, прежде чем переходить к фоновому потоку, чтобы избежать этой проблемы.

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

Конечно, учитывая, что вы, кажется, не имеют каких-либо долго работает процессор связан работу, и все работы, которые вы здесь уже асинхронная задача на основе работы IO, вы должны быть способный просто полностью удалить вызов Task.Run, позволяя вам работать с небольшим количеством процессоров, do должен работать в потоке пользовательского интерфейса, не блокируя его вообще из-за длительных операций, которые все уже являются асинхронными.

О, и так как вам нужен только первый элемент usersCollection, вы должны использовать First, а не ToList, чтобы избежать материализации всего результирующего набора в память. Вы также должны выполнить это First и свою фильтрацию до, вызывая ToCollectionAsync, чтобы, если это вообще возможно, выполнить всю эту фильтрацию через поставщика запросов, а не материализовать всю коллекцию в ваше приложение.

+0

У меня есть подозрение, что 'App.FacebookProvider.GetCurrentUserId' и' App.FacebookProvider.GetCurrentUserName' являются долговременными, а не async. Или, возможно, что 'userCollection' огромен. –

+0

Это работает, но на самом деле не отвечает, почему переменная экземпляра становится нулевой. Спасибо – winnicki

+0

@ DanielMann Они не асинхронны, а также не долгое время. Просто хватаю за уже заполненную переменную. usersCollection также составляет только около 20 строк. – winnicki