2009-11-30 14 views
19

मैं निम्नलिखित सी # परीक्षण कोड है:सी #: जेनेरिक प्रकार जिनमें एक निर्माता है?

class MyItem 
    { 
    MyItem(int a) {} 
    } 

    class MyContainer<T> 
    where T : MyItem, new() 
    { 
    public void CreateItem() 
    { 
     T oItem = new T(10); 
    } 
    } 

दृश्य स्टूडियो यह संकलन नहीं कर सकता, त्रुटि जहां 'नए' प्रयोग किया जाता है लाइन पर है:

'T': cannot provide arguments when creating an instance of a variable type 

इसे करने के लिए सी # में संभव है गैर-पैरामीटर रहित कन्स्ट्रक्टर के साथ जेनेरिक प्रकार का ऑब्जेक्ट बनाएं? सी ++ टेम्पलेट्स में ऐसी चीज करने में कोई समस्या नहीं है, इसलिए मैं बहुत उत्सुक हूं कि मैं सी # में एक ही चीज़ क्यों नहीं कर सकता। शायद कुछ अतिरिक्त 'कहां' आवश्यक है या वाक्यविन्यास अलग है?

उत्तर

16

यह प्रतिबिंब के साथ किया जा सकता है उदाहरण के लिए:

public void CreateItem() 
{ 
    int constructorparm1 = 10; 
    T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T; 
} 

लेकिन कोई सामान्य बाधा यह सुनिश्चित करें कि T वांछित निर्माता को लागू करता है, तो मैं तब तक ऐसा करने की सलाह नहीं दूंगा जब तक कि आप इंटरफ़ेस को लागू करने वाले हर प्रकार में उस निर्माता को घोषित करने के लिए सावधान रहें।

+0

जैसा कि मुझे याद है, 'नई()' बाधा 'एक्टिवेटर। क्रिएट इंस्टेंस()' कॉल में अनुवाद करती है। –

9

ऐसी कोई सामान्य बाधा नहीं है, इसलिए यह संभव नहीं है (यह एक सीएलआर सीमा है)। यदि आप इसे चाहते हैं, तो आपको एक फैक्ट्री क्लास (जिसमें पैरामीटर रहित कन्स्ट्रक्टर है) प्रदान करना होगा, और इसे दूसरे सामान्य प्रकार पैरामीटर के रूप में पास करना होगा।

25

सी #, और उस मामले के लिए वीबी.Net, विशिष्ट पैरामीटर के साथ एक निर्माता बनाने के लिए जेनेरिक को बाधित करने की धारणा का समर्थन नहीं करते हैं। यह केवल खाली कन्स्ट्रक्टर रखने के लिए बाधा का समर्थन करता है।

मूल्य बनाने के लिए कॉलर पास फैक्ट्री लैम्ब्डा में कॉलर पास करना है।

public void CreateItem(Func<int,T> del) { 
    T oItem = del(10); 
} 

कॉल साइट

CreateItem(x => new SomeClass(x)); 
+0

बहुत चालाक दृष्टिकोण! – Greg

2

एक पैटर्न का उपयोग मैं विवश वर्ग एक अंतरफलक जो उचित हस्ताक्षर के साथ एक Init विधि को परिभाषित करता है को लागू करने के लिए है:

interface IMyItem 
{ 
    void Init(int a); 
} 

class MyItem : IMyItem 
{ 
    MyItem() {} 
    void Init(int a) { } 
}  

class MyContainer<T> 
    where T : MyItem, IMyItem, new() 
{ 
    public void CreateItem() 
    { 
     T oItem = new T(); 
     oItem.Init(10); 
    } 
} 
+0

आम तौर पर एक बुरा विचार, क्योंकि अब आप बना सकते हैं लेकिन अनियमित वस्तुओं। –

4

IMO, यहाँ का सबसे अच्छा तरीका एक इनिशियलाइज़ विधि, यानी

interface ISomeInterface { 
    void Init(int i); 
} 
class Foo : ISomeInterface { 
    void ISomeInterface.Init(int i) { /* ... */ } 
} 
static class Program { 
    static T Create<T>(int i) where T : class, ISomeInterface, new() { 
     T t = new T(); 
     t.Init(i); 
     return t; 
    } 
    static void Main() { 
     Foo foo = Create<Foo>(123); 
    } 
} 
है

हालांकि, अगर आप Expression साथ तुम क्या चाहते कर सकते हैं (लेकिन बिना संकलन-टाइम समर्थन):

using System; 
using System.Linq.Expressions; 
class Foo { 
    public Foo(int i) { /* ... */ } 
} 
static class Program { 
    static T Create<T>(int i) { 
     return CtorCache<T>.Create(i); 
    } 
    static class CtorCache<T> { 
     static Func<int, T> ctor; 
     public static T Create(int i) { 
      if (ctor == null) ctor = CreateCtor(); 
      return ctor(i); 
     } 
     static Func<int, T> CreateCtor() { 
      var param = Expression.Parameter(typeof(int), "i"); 
      var ci = typeof(T).GetConstructor(new[] {typeof(int)}); 
      if(ci == null) throw new InvalidOperationException("No such ctor"); 
      var body = Expression.New(ci, param); 
      return Expression.Lambda<Func<int, T>>(body, param).Compile(); 
     } 
    } 
    static void Main() { 
     Foo foo = Create<Foo>(123); 
    } 
} 

ध्यान दें कि यह कैश प्रदर्शन के लिए प्रतिनिधि को पुन: उपयोग करता है।

+0

क्या यह 'Activator.CreateInstance() 'का उपयोग करने से काफी भिन्न है? अगर मैं सही ढंग से समझता हूं, न तो संकलन-समय का समर्थन होता है, और यदि अपेक्षित कन्स्ट्रक्टर मौजूद नहीं है तो दोनों रन-टाइम त्रुटि फेंक देते हैं। – Greg

+0

@ ग्रेग - हाँ, यदि आप इसे बहुत उपयोग कर रहे हैं (उदाहरण के लिए, एक कारखाना): एक बार बनाया गया, प्रतिनिधि प्री-कैश और जूट है - कोई और प्रतिबिंब नहीं। –

संबंधित मुद्दे