2010-08-11 6 views
15

मैं तरीके आलसी प्रारंभ करने के लिए की तलाश में और Lazy<T> जो .NET में शामिल किया गया है पाया गया था 4.लेज़ी <T> कार्यान्वयन और .NET जेनरिक

मैं .NET 3.5 के लिए Lazy<T> के अपने खुद के कार्यान्वयन रोलिंग की सोच रहा था (साथ

लेज़ी निर्माताओं की मूल रूप से दो प्रकार के होते हैं:: एक सरल बहु धागा नीति), और मैं निम्नलिखित समस्या से टकरा

class Lazy<T> { 

    public Lazy(){...} // ctor #1 

जो एक बनाने के लिए टी के डिफ़ॉल्ट निर्माता का उपयोग करता है एन का उदाहरण, और

public Lazy(Func<T> func){...} // ctor #2 

जो कॉलर को यह तय करने देता है कि टी का उदाहरण कैसे बनाया गया है।

अब यहाँ समस्या है:

मैं संकलन समय 1 ctor के लिए जाँच मैं श्रेणी स्तर पर एक प्रतिबंध

class Lazy<T> where T: new() {...} 

जोड़ना होगा चाहते हैं। यह मुझे उदाहरण बनाने के लिए new T() का उपयोग करने की अनुमति देगा; लेकिन यह प्रतिबंध दूसरे ctor के लिए जरूरी नहीं है, और इससे भी बदतर, यह उन प्रकारों को प्रतिबंधित करता है जिन्हें मैं उपयोग कर सकता हूं (डिफ़ॉल्ट ctor वाले लोगों के लिए)

यदि मैं दूसरे ctor के साथ किसी भी प्रकार का उपयोग करने में सक्षम होना चाहता हूं, तो मैं कोई प्रतिबंध नहीं लगाएगा, और पहले सीटीआर में T में एक डिफ़ॉल्ट सीटीआर सुनिश्चित करने के लिए प्रतिबिंब का उपयोग करेगा। हालांकि, इस दृष्टिकोण में संकलन-समय की जांच की कमी होगी, और अगर पहले ctor को गलत प्रकार के साथ प्रयोग किया जाता है तो केवल रनटाइम अपवाद फेंक देगा।

मेरा सवाल है: क्या मैं दोनों दुनिया के सर्वश्रेष्ठ प्राप्त कर सकता हूं?

आदर्श रूप से, मैं ctor # 1 के प्रत्येक उपयोग के लिए संकलन-समय की जांच प्राप्त करना चाहता हूं, लेकिन साथ ही उन प्रकारों के लिए ctor # 2 का उपयोग करने में सक्षम होना चाहिए जिनके पास डिफ़ॉल्ट ctor नहीं है।

माइक्रोसॉफ्ट कार्यान्वयन यह कैसे करता है? (मुझे आसानी से .NET 4 स्रोतों या डीएलएस तक पहुंच नहीं है)।

संपादित करें:

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

+3

आप .NET 4 कार्यान्वयन –

+0

@ थॉमस को देखने के लिए परावर्तक का उपयोग कर सकते हैं। मुझे खुद को उद्धृत करना पसंद है। मुझे महत्वपूर्ण लगता है: "मुझे आसानी से .NET 4 स्रोतों या डीएलएस तक पहुंच नहीं है" ... या कम से कम यह सच था जब मैंने सवाल पूछा। इस बीच, लुकास के संकेत के लिए धन्यवाद, मुझे असेंबली का पकड़ मिला और मेरे निष्कर्षों के साथ सवाल को अद्यतन किया। –

+0

ठीक है, मैंने "या dlls" भाग को याद किया ... क्षमा करें –

उत्तर

12

मैं इनबिल्ट कार्यान्वयन बस के लिए Activator.CreateInstance<T> का उपयोग करता है उम्मीद सादगी। स्पष्ट तरीका मैं इस धोखाधड़ी के बारे में सोच सकते हैं एक अलग कारखाने के साथ है:

// non-generic factory class with generic methods 
public static class Lazy { 
    public static Lazy<T> Create<T>() where T : new() { 
     return Create<T>(() => new T()); 
    } 
    public static Lazy<T> Create<T>(Func<T> ctor) { ... } 
} 
public class Lazy<T> { ... } 
+0

एक व्यक्ति की धोखा एक और डिजाइन पैटर्न है। :) – LBushkin

0

मेरा प्रश्न है: क्या मुझे दोनों दुनिया का सर्वश्रेष्ठ मिल सकता है?

सं

मूल रूप से आप कोई संकलन समय चेक करने योग्य बाधा है।

7

आप निर्माता के लिए एक अधिभार के बजाय एक स्थिर कारखाने विधि इस्तेमाल कर सकते हैं:

public class Lazy<T> 
{ 
    public Lazy(Func<T> f) { /*...*/ } 

    public static Lazy<R> Default<R>() where R : T, new() 
    { 
     return new Lazy<R>(() => new R()); 
    } 
} 

अब, यह टूट जाता है संगतता (कुछ हद तक) नेट 4 के साथ।Lazy<T> का 0 संस्करण, लेकिन यह दोनों प्रकार के उपयोग के लिए संकलन समय सुरक्षा प्राप्त करता है।

आप Lazy<T> आंतरिक संरक्षित के लिए कंस्ट्रक्टर्स बनाकर इस थोड़ा क्लीनर कर सकता है, और एक स्थिर कारखाने वर्ग है कि आप हमेशा उदाहरणों बनाने के लिए उपयोग प्रदान करते हैं:

public static class Lazy { 
    static Lazy<T> Create<T>(Func<T>) { ... } 
    static Lazy<T> Create<T>() where T : new() { ... } 
} 
+1

एर्म ... मेरी अज्ञानता क्षमा करें, लेकिन मैं आलसी से आलसी के संरक्षित सीटीओ को कैसे कॉल कर सकता हूं? –

+0

मेरा मतलब 'आंतरिक संरक्षित' लिखना था - मैं इसे संशोधित करूंगा। – LBushkin

2

आप क्यों नहीं बस समानांतर extesions डाउनलोड करने और 3.5 के लिए Lazy<T> स्थापित नहीं करते? Direct link

+1

क्योंकि किसी भी तृतीय पक्ष पुस्तकालयों का उपयोग करने के लिए कंपनी की स्वीकृति प्राप्त करने में दर्द होता है। :( –

+0

ओह ... लेकिन अब मैं वेनिला कार्यान्वयन में मेरी नाक का शिकार कर सकता हूं :) –

0

ऐसा कुछ आपके लिए काम करना चाहिए। हमने 4.0 पर जाने से पहले एक साल या उससे भी अधिक के लिए हमारे स्थानीय कोड बेस में इसका इस्तेमाल किया था।

public class Lazy<T> { 
    private Func<T> func; 
    private T result; 
    private bool hasValue; 
    public Lazy(Func<T> func) { 
    this.func = func; 
    this.hasValue = false; 
    } 
    public T Value { 
    get { 
     if (!this.hasValue) { 
     this.result = this.func(); 
     this.hasValue = true; 
     } 
     return this.result; 
    } 
    } 
}