2014-06-10 2 views
0

WinRT에 익숙하지 않습니다. 예기치 않은 동작이 발생했습니다. 나는 static 변수 _Verses을 클래스의 정적 생성자에서 초기화했습니다. 그래서 예상되는 동작은 When is a static constructor called in C#?정적 변수 초기화의 예기치 않은 동작

에 설명 된대로 _Verses 정적 방법 첫 번째 참조 전에 초기화 될 것이다 그러나 나는 static async 기능 LoadData (WinRT)를 호출 할 때 예외를 얻었다.

개체 참조가 개체의 인스턴스로 설정되지 않았습니다.

내 코드는 다음과 같습니다

async void DoInit() 
{ 
    await DigitalQuran.Book.CreateInstance(); 
} 

같은 코드가 바탕 화면에서 작업하지만 WinRT 작동하지 않습니다 :

public VerseCollection 
{ 
    public const int TotalVerses = 6236; 

    static Verse[] _Verses; 
    static VerseCollection() 
    { 
     _Verses = new Verse[TotalVerses]; 
    } 

    internal static async void LoadData(StorageFile file) 
    { 
     using (var reader = new BinaryReader(await file.OpenStreamForReadAsync())) 
     { 
      int wId = 0; 
      for (int i = 0; i < VerseCollection.TotalVerses; i++) 
      { 
       var retValue = new string[reader.ReadInt32()]; 
       for (int j = 0; j < retValue.Length; j++) 
        retValue[j] = reader.ReadString(); 

       _Verses[i] = new Verse(i, wId, retValue); 

       wId += _Verses[i].Words.Count; 
      } 
     } 
    } 
} 

public Book 
{  
    public static async Task<Book> CreateInstance() 
    { 
     VerseCollection.LoadData(await DigitalQuranDirectories.Data.GetFileAsync("quran-uthmani.bin")); 
    } 
} 

나는 같은 기능 CreateInstance를 호출합니다. 데스크탑 Book 클래스의 전체 코드 here하고 VerseCollection 클래스 here

는 편집이다 : 나는 디버거를 코드 예외가 발생하지 않습니다를 실행하면 전체 코드는 여기

public class Book : VerseSpan 
{ 
    public static async Task<Book> CreateInstance() 
    { 
     _Instance = new Book(); 

     VerseCollection.LoadData(await DigitalQuranDirectories.Data.GetFileAsync("quran-uthmani.bin")); 
     PrivateStorage.LoadQuranObjectsFromMetadata(); 
     // Some Other Operations too 

     return _Instance; 
    } 
} 


public class VerseCollection 
{ 
    static Verse[] _Verses = new Verse[TotalVerses]; 

    internal static async void LoadData(StorageFile file) 
    { 
     using (var reader = new BinaryReader(await file.OpenStreamForReadAsync())) 
     { 
      int wId = 0; 
      for (int i = 0; i < VerseCollection.TotalVerses; i++) 
      { 
       var retValue = new string[reader.ReadInt32()]; 
       for (int j = 0; j < retValue.Length; j++) 
        retValue[j] = reader.ReadString(); 

       _Verses[i] = new Verse(i, wId, retValue); 

       wId += _Verses[i].Words.Count; 
      } 
     } 
    } 
} 

public class Verse 
{ 
    public Verse(int number, int firstWordIndex, string[] words) 
    { 
     GlobalNumber = number + 1; 

     Words = new WordCollection(firstWordIndex, words, this);    
    } 
} 

public class WordCollection : ReadOnlyCollection<Word> 
{ 
    public const int TotalWords = 77878; 

    static Word[] _Words = new Word[TotalWords]; 
    static string[] _WordsText = new string[TotalWords]; 

    public WordCollection(int startIndex, int count) 
     : base(count) 
    { 
     this.startIndex = startIndex; 
    } 

    internal WordCollection(int startId, string[] words, Verse verse) : this(startId, words.Length) 
    { 
     int max = words.Length + startId; 
     for (int i = startId; i < max; i++) 
     { 
      _Words[i] = new Word(i, verse); 
      _WordsText[i] = words[i - startId];    
     } 
    } 
} 

public abstract class ReadOnlyCollection<T> : IEnumerable<T> 
{ 
    public ReadOnlyCollection(int count) 
    { 
     Count = count; 
    } 
} 

public class PrivateStorage 
{ 
    internal static async void LoadQuranObjectsFromMetadata() 
    {    
     using (var reader = new BinaryReader(await (await DigitalQuranDirectories.Data.GetFileAsync(".metadata")).OpenStreamForReadAsync())) 
     { 
      /* 1 */ ChapterCollection.LoadData(EnumerateChapters(reader)); 
      /* 2 */ PartCollection.LoadData(EnumerateParts(reader)); 
      /* Some other tasks */ 
     } 
    } 

    static IEnumerator<ChapterMeta> EnumerateChapters(BinaryReader reader) 
    { 
     for (int i = 0; i < ChapterCollection.TotalChapters; i++) 
     { 
      yield return new ChapterMeta() 
      { 
       StartVerse = reader.ReadInt32(), 
       VerseCount = reader.ReadInt32(), 
       BowingCount = reader.ReadInt32(), 
       Name = reader.ReadString(), 
       EnglishName = reader.ReadString(), 
       TransliteratedName = reader.ReadString(), 
       RevelationPlace = (RevelationPlace)reader.ReadByte(), 
       RevelationOrder = reader.ReadInt32() 
      }; 
     } 
    } 

    static IEnumerator<PartMeta> EnumerateParts(BinaryReader reader) 
    { 
     for (int i = 0; i < PartCollection.TotalParts; i++) 
     { 
      yield return new PartMeta() 
      { 
       StartVerse = reader.ReadInt32(), 
       VerseCount = reader.ReadInt32(), 
       ArabicName = reader.ReadString(), 
       TransliteratedName = reader.ReadString() 
      }; 
     } 
    } 
} 


public class ChapterCollection : ReadOnlyCollection<Chapter> 
{ 
    public const int TotalChapters = 114; 

    static Chapter[] _Chapters = new Chapter[TotalChapters]; 

    internal static void LoadData(IEnumerator<ChapterMeta> e) 
    { 
     for (int i = 0; i < TotalChapters; i++) 
     { 
      e.MoveNext(); 
      _Chapters[i] = new Chapter(i, e.Current); 
     } 
    } 
} 


public class PartCollection : ReadOnlyCollection<Part> 
{ 
    public const int TotalParts = 30; 

    static Part[] _Parts = new Part[TotalParts]; 
    internal static void LoadData(IEnumerator<PartMeta> e) 
    {    
     for (int i = 0; i < TotalParts; i++) 
     { 
      e.MoveNext(); 
      _Parts[i] = new Part(i, e.Current); 
     } 
    } 
} 

입니다. 이 화상하지만 실행되기 때문에 또한 예외 후 비주얼 스튜디오 라인 _Chapters[i] = new Chapter(i, e.Current); (_Chaptersnull이다)

+1

어떻게 _Verses를 초기화하는지 알지 못합니다. 비동기 작업을 사용하고 계신지요? 그렇다면 LoadData를 호출 할 때 비동기 작업이 완료되지 않았을 수 있습니다 ... – Gusman

+0

정적 변수 –

+0

의 초기화 코드를 볼 필요가 있습니다. _Verses가 비동기 작업을 사용하여 초기화되지 않았습니다. 그것은 단지 배열의 초기화입니다. 초기화 코드가 추가되었습니다. –

답변

1

비동기 호출에 문제가있었습니다. 파일 읽기는 WinRT의 비동기 작업입니다. 우리는 void 반환 유형 await 성명과 함께 async 메서드를 호출 할 수 없습니다. 따라서 다음 명령어는 마지막 실행 완료를 기다리지 않고 실행되고 Task입니다. 이로 인해 NullReferanceExecption이됩니다.

나는 void에서 Task 모든 async 작업의 반환 형식을 변경하여 내 문제를 해결하기 위해 관리하고 아래의 코드처럼 await로 불렀다.

public class Book : VerseSpan 
{ 
    public static async Task<Book> CreateInstance() 
    { 
     _Instance = new Book(); 

     await VerseCollection.LoadData(await DigitalQuranDirectories.Data.GetFileAsync("quran-uthmani.bin")); 
     await PrivateStorage.LoadQuranObjectsFromMetadata(); 
     // Some Other Operations too 

     return _Instance; 
    } 
} 


public class VerseCollection 
{ 
    static Verse[] _Verses = new Verse[TotalVerses]; 

    internal static async Task LoadData(StorageFile file) 
    { 
     using (var reader = new BinaryReader(await file.OpenStreamForReadAsync())) 
     { 
      int wId = 0; 
      for (int i = 0; i < VerseCollection.TotalVerses; i++) 
      { 
       var retValue = new string[reader.ReadInt32()]; 
       for (int j = 0; j < retValue.Length; j++) 
        retValue[j] = reader.ReadString(); 

       _Verses[i] = new Verse(i, wId, retValue); 

       wId += _Verses[i].Words.Count; 
      } 
     } 
    } 
} 

public class PrivateStorage 
{ 
    internal static async Task LoadQuranObjectsFromMetadata() 
    {    
     using (var reader = new BinaryReader(await (await DigitalQuranDirectories.Data.GetFileAsync(".metadata")).OpenStreamForReadAsync())) 
     { 
      /* Some tasks */ 
     } 
    } 
} 
0

에서 작동 LoadData 클래스 ChapterCollection 라인 _Verses[i] = new Verse(i, wId, retValue);에 기능 LoadData 클래스 VerseCollection 일부 시간 (_Versesnull이다) 및 일부 시간을 나타낸다 WinRT가 아니라면 비동기 호출에 문제가 있다고 생각하게됩니다. 이 작업을 비동기 적으로 수행하기 때문에 LoadData를 호출하기 전에 생성자 (정적 또는 비공유)가 실행을 마칠 수있는 권한이 없습니다. LoadData 함수를 호출하기 전에 생성자가 실행을 완료했는지 확인하십시오. 그러면 일관된 동작이 제공됩니다.

+0

정적 생성자를 이전에 끝내려면 어떻게해야합니까? MSDN 주제에 따르면 우리는 정적 생성자 호출을 제어하거나 수동으로 호출 할 수 없습니다. –

+2

"비동기 적으로이 작업을 수행하기 때문에 LoadData를 호출하기 전에 생성자 (정적 또는 비공유)가 실행 완료 될 것입니다." 그것은 분명히 일반 CLR의 경우는 아닙니다. WinRT가 정적 생성자에 대해 다른 보증을 제공하는지 여부가 궁금합니다 ... –