2008-10-08 27 views
15

एक सी # अनुप्रयोग पर काम करते समय मैं बस देखा है कि कई स्थानों पर स्थिर initializers इस तरह एक दूसरे पर निर्भरता हैं:आदेश

static private List<int> a = new List<int>() { 0 }; 
static private List<int> b = new List<int>() { a[0] }; 

कुछ भी विशेष है कि काम कर के बिना। क्या यह सिर्फ भाग्य है? क्या सी # को हल करने के नियम हैं?

संपादित करें: (पुन: पैनोस) फ़ाइल में अक्षीय क्रम राजा लगता है? फाइलों के बारे में क्या?

देख में मैं इस तरह एक चक्रीय निर्भरता की कोशिश की:

static private List<int> a = new List<int>() { b[0] }; 
static private List<int> b = new List<int>() { a[0] }; 

और कार्यक्रम में एक ही (परीक्षण सूट बोर्ड भर में विफल रहा है और मैं आगे देखने के लिए नहीं किया है) नहीं चला।

+0

मुझे लगता है कि फाइलों (यानी विभिन्न वर्गों में) यह वही होगा। कक्षा ए के प्रारंभिक प्रकार के दौरान, कक्षा बी को प्रारंभ करने के लिए कहा जाएगा, और कक्षा बी को कक्षा ए – Panos

+0

के लिए एक संक्षिप्त संदर्भ मिलेगा, अब, एक ही कक्षा (आंशिक वर्ग) की फाइलों में, शायद पूर्व-प्रोसेसर तक है निर्धारित करें कि यह विफल रहता है या नहीं। – Panos

+0

तो यदि कोई संदर्भ बीबी है तो एए प्राप्त हो जाएगा बीबी टक्कर लगी होगी? – BCS

उत्तर

13

ऐसा लगता है कि यह लाइनों के अनुक्रम पर निर्भर करता है। इस कोड काम करता है:

static private List<int> a = new List<int>() { 1 }; 
static private List<int> b = new List<int>() { a[0] }; 

जबकि इस कोड (यह एक NullReferenceException फेंकता)

static private List<int> a = new List<int>() { b[0] }; 
static private List<int> b = new List<int>() { 1 }; 

तो काम नहीं करता है, स्पष्ट रूप से चक्रीय निर्भरता के लिए कोई नियम मौजूद हैं। क्या "फ़ाइलों में" हो रहा है - यह अजीब लेकिन है कि संकलक शिकायत नहीं करता है ...


संपादित है? हम इन दो वर्गों यह घोषणा करते हैं:

public class A { 
    public static List<int> a = new List<int>() { B.b[0] }; 
} 
public class B { 
    public static List<int> b = new List<int>() { A.a[0] }; 
} 

और इस कोड के साथ उन तक पहुँचने का प्रयास करें:

try { Console.WriteLine(B.b); } catch (Exception e) { Console.WriteLine(e.InnerException.Message.); } 
try { Console.WriteLine(A.a); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); } 
try { Console.WriteLine(B.b); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); } 

हम इस उत्पादन हो रही है:

The type initializer for 'A' threw an exception. 
Object reference not set to an instance of an object. 
The type initializer for 'A' threw an exception. 

तो B का प्रारंभ एक का कारण बनता है स्थिर कन्स्ट्रक्टर A में अपवाद और डिफ़ॉल्ट मान (शून्य) के साथ lefts फ़ील्ड a। चूंकि anull है, b को भी ठीक से प्रारंभ नहीं किया जा सकता है।

यदि हमारे पास चक्रीय निर्भरता नहीं है, तो सब कुछ ठीक काम करता है।


संपादित करें: बस मामले में आप टिप्पणियां पढ़ें नहीं किया था, Jon Skeet एक बहुत ही दिलचस्प पढ़ने प्रदान करता है: The differences between static constructors and type initializers

+0

दिलचस्प है, इसलिए प्रारंभिक तब तक नहीं होता जब तक सामान संदर्भित न हो ... – BCS

+0

यह सुनिश्चित है। जब स्थिरता पहली बार संदर्भित की जाती है तो स्थिर कन्स्ट्रक्टर को बुलाया जाता है। – Panos

+2

स्थिर वैरिएबल प्रारंभकर्ताओं और स्थिर रचनाकारों के बीच अंतर के बारे में यहां सावधान रहें। एक स्थिर कन्स्ट्रक्टर की उपस्थिति/अनुपस्थिति के आधार पर प्रारंभिकरण टाइप करते समय चारों ओर अलग-अलग नियम होते हैं। Http://pobox.com/~skeet/csharp/beforefieldinit.html –

0

हाँ, आप भाग्यशाली थे। सी # कक्षा में दिखाई देने वाले क्रम में कोड निष्पादित करने के लिए प्रतीत होता है।

static private List<int> a = new List<int>() { 0 }; 
static private List<int> b = new List<int>() { a[0] }; 

काम करेगा लेकिन ...

static private List<int> b = new List<int>() { a[0] }; 
static private List<int> a = new List<int>() { 0 }; 

असफल हो जायेगी।

मैं आपकी सभी निर्भरताओं को एक ही स्थान पर रखने की अनुशंसा करता हूं, स्थिर रचनाकार इसके लिए जगह है।

static MyClass() 
{ 
    a = new List<int>() { 0 }; 
    b = new List<int>() { a[0] }; 
} 
2

व्यक्तिगत रूप से मैं स्थैतिक प्रारंभकर्ताओं से छुटकारा पाता हूं क्योंकि यह स्पष्ट नहीं है और इन चरों को प्रारंभ करने के लिए एक स्थिर कन्स्ट्रक्टर जोड़ें।

static private List<int> a; 
static private List<int> b; 

static SomeClass() 
{ 
    a = new List<int>() { 0 }; 
    b = new List<int>() { a[0] }; 
} 

तब आपको यह अनुमान लगाने की ज़रूरत नहीं है कि क्या हो रहा है और आप अपने इरादों में स्पष्ट हैं।

+2

देखें ध्यान दें कि कोड के उन टुकड़े * ठीक * समकक्ष नहीं होते हैं जब वे दौड़ते हैं: http://pobox.com/~skeet/csharp /beforefieldinit.html –

14

नियम यहाँ section 10.4 of the C# spec देखें:

जब एक वर्ग आरंभ नहीं हो जाता है तो उस वर्ग के सभी स्थिर क्षेत्रों पहले उनके डिफ़ॉल्ट मानों के प्रारंभ कर रहे हैं, और उसके बाद स्थिर क्षेत्र initializers शाब्दिक क्रम में क्रियान्वित कर रहे हैं। इसी तरह, जब किसी वर्ग का एक उदाहरण बनाया जाता है, तो उस इंस्टेंस में सभी इंस्टेंस फ़ील्ड्स को पहले उनके डिफ़ॉल्ट मानों में प्रारंभ किया जाता है, और फिर आवृत्ति फ़ील्ड प्रारंभकर्ता को पाठ क्रम में निष्पादित किया जाता है। वैरिएबल फ़ील्ड के लिए स्थिर फ़ील्ड के लिए यह संभव है कि उनके डिफ़ॉल्ट मान स्थिति में देखा जाए। हालांकि, यह शैली के मामले के रूप में दृढ़ता से निराश है।

तो दूसरे शब्दों में, अपने उदाहरण 'बी' में अपनी डिफ़ॉल्ट स्थिति (शून्य) और इतने के प्रारंभकर्ता में इसे करने के लिए संदर्भ 'एक' कानूनी है, लेकिन एक NullReferenceException में परिणाम होगा करने के लिए आरंभ नहीं हो जाता।

ये नियम जावा के लिए अलग हैं (आगे संदर्भों के बारे में जावा के नियमों के लिए section 8.3.2.3 of the JLS देखें, जो अधिक प्रतिबंधित हैं)।

+0

* मैंने पूछा प्रश्न के लिए महान उत्तर *। हालांकि ऐसा लगता है कि मैंने उस प्रश्न से नहीं पूछा था जिसे मैं चाहता था: फाइलों के बारे में क्या? – BCS

+0

मैं सी # नहीं हूं (बस पता था कि कहां देखना है) लेकिन http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx देखें - "निर्माण करना संभव है परिपत्र निर्भरताएं जो वैरिएबल फ़ील्ड को वेरिएबल प्रारंभकर्ताओं के साथ उनके डिफ़ॉल्ट मान स्थिति में देखने की अनुमति देती हैं "। क्या उससे मदद हुई? – Cowan

+0

@ कौवन वास्तव में नहीं। यह क्रॉस फ़ाइल मुद्दे को संबोधित नहीं करता है। – BCS