2016-10-18 1 views
-1

아래 코드는 VS2015 업데이트 3 (Resharper 2016, Windows 10 x64, .NET 4.5)에 System.StackOverflowException을 던지고 있습니다. IMO, 그것은 City ->Authority ->Country ->City의 정적 생성자의 주기적 초기화 때문입니다. 충분히 이상한, 그것은 VS2015 업데이트와 협력 2.큰 목록의 '지연 생성'초기화로 정적 생성자에서 StackOverflowException을 피하는 방법

이것은 내가 비주얼 스튜디오에있어 예외입니다 : 그것은 더 중요 업데이트 2가 아니라 업데이트 3와 함께 작동, 왜

System.StackOverflowException {"Exception of type 'System.StackOverflowException' was thrown."} 
Data : {System.Collections.ListDictionaryInternal} 
Count: 0 
IsFixedSize: false 
IsReadOnly: false 
IsSynchronized: false 
Keys : {System.Collections.ListDictionaryInternal.NodeKeyValueCollection} 
    [] 
SyncRoot : {object} 
Values: {System.Collections.ListDictionaryInternal.NodeKeyValueCollection} 
    [] 
HelpLink: null 
HResult: -2147023895 
InnerException: null 
Message: Exception of type 'System.StackOverflowException' was thrown. 
Source: null 
StackTrace: null 
TargetSite: null 

이 궁금해 , 그것을 해결하기 위해 무엇을 할 수 있습니까? 이 테스트 코드 :

public static class PeopleTestData 
{ 
    public static readonly Lazy<List<Person>> People; 
    static PeopleTestData() 
    { 
     People = new Lazy<List<Person>>(() => new List<Person> 
     { 
      new Person {Name = "Person1", City = CityTestData.GetByID(1), ID = 1}, 
      new Person {Name = "Person2", City = CityTestData.GetByID(2), ID = 2}, 
      //~6000 records 
     }); 
    } 
    public static Person GetByID(int personID) 
    { 
     return People.Value.Single(p => p.ID == personID); 
    } 
} 

public static class CityTestData 
{ 
    public static readonly Lazy<List<City>> Cities; 
    static CityTestData() 
    { 
     Cities = new Lazy<List<City>>(() => new List<City> 
     { 
      new City {Name = "City1", Authority = AuthorityTestData.GetByID(1), Country = CountryTestData.GetByID(1), ID = 1}, 
      new City {Name = "City2", Authority = AuthorityTestData.GetByID(2), Country = CountryTestData.GetByID(2), ID = 2}, 
      //~5000 records 
     }); 
    } 
    public static City GetByID(int cityID) 
    { 
     return Cities.Value.Single(p => p.ID == cityID); 
    } 
} 

public static class CountryTestData 
{ 
    public static readonly Lazy<List<Country>> Countries; 
    static CountryTestData() 
    { 
     Countries = new Lazy<List<Country>>(() => new List<Country> 
     { 
      new Country {Name = "Country1", Cities = CityTestData.Cities.Value.Where(c=>c.Country.ID == 1).ToList(), ID = 1}, 
      new Country {Name = "Country2", Cities = CityTestData.Cities.Value.Where(c=>c.Country.ID == 2).ToList(), ID = 2}, 
      //~200 records 
     }); 
    } 
    public static Country GetByID(int countryID) 
    { 
     return Countries.Value.Single(p => p.ID == countryID); 
    } 
} 

public static class AuthorityTestData 
{ 
    public static readonly Lazy<List<Authority>> Authorities; 
    static AuthorityTestData() 
    { 
     Authorities = new Lazy<List<Authority>>(() => new List<Authority> 
     { 
      new Authority {Name = "Authority1", Country = CountryTestData.GetByID(1), ID = 1}, 
      new Authority {Name = "Authority2", Country = CountryTestData.GetByID(2), ID = 2}, 
      //~3000 records 
     }); 
    } 
    public static Authority GetByID(int authorityID) 
    { 
     return Authorities.Value.Single(p => p.ID == authorityID); 
    } 
} 

그리고 도메인 엔티티 :

public class Person 
{ 
    public int ID; 
    public string Name; 
    public City City; 
} 
public class City 
{ 
    public int ID; 
    public string Name; 
    public Country Country; 
    public Authority Authority; 
} 
public class Authority 
{ 
    public int ID; 
    public string Name; 
    public Country Country; 
} 
public class Country 
{ 
    public int ID; 
    public string Name; 
    public List<City> Cities; 
} 
+0

코드에는 람다식이 포함되어 있습니다. 즉, 선언 된 위치에서 실행되지 않습니다. 실제 값이 요청되면 실행해야합니다. 하지만 여기에 간섭하는 더 복잡한 스케줄링이있을 수 있는지 확실하지 않습니다. –

답변

0

당신은 확실히 어떤 순환 종속성을 넣으면 안됩니다 여기

public class Program 
{ 
    public static void Main(string []args) 
    { 
     var p1 = PeopleTestData.GetByID(1); 
     Console.WriteLine(p1.Name); 
    } 
} 

Lazy 및 정적 생성자를 사용하여 초기화됩니다 .

업데이트 할 때마다 매번가 정상적으로 작동합니까? 나는 의심한다.

지연 초기화를 사용하기 때문에주기없이 실행되는 순서가있을 수 있습니다. 주기적 의존성을 가지고 있음에도 불구하고 실행하기에는 너무 운이 좋다.

0

정적 생성자의 순환 종속성으로 인해 스택 오버플로가 아니라 교착 상태가 발생합니다. 귀하의 경우에는 정적 생성자가 완료되었지만 지연 초기화는 수행되지 않았습니다.

Lazy<T> 인스턴스가 완전히 초기화 될 때까지 해당 인스턴스를 초기화하려는 재진입 시도가 처음부터 시작됩니다. 그리고 은 스택 오버 플로우가 발생하는 곳이입니다.

이 문제를 확실하게 재현하지만 (시나리오를 정확하게 반영하는) 좋은 정보가 없으면 특정 해결 방법을 제공하는 것이 불가능합니다. 그러나 확실히, 당신은 이 아니고 타입의 초기화가 서로의 초기화에 의존해야합니다. (다른 답변자와 마찬가지로이 버전이 Visual Studio & hellip의 모든 버전에서 작동했음을 회의적입니다. VS 버전에 종속적 인 것은 아닙니다.)

에 대한 방법을 찾아야합니다. 초기화를 완료하고 다른 유형에 따라 사용할 수있는 유형 중 적어도 하나를 포함해야합니다.

관련 문제