2008-11-05 12 views
140

के लिए टाइप पैरामीटर के रूप में टाइप करें शीर्षक शीर्षक अस्पष्ट है। क्या मैं जानना चाहता हूँ कि अगर यह संभव है:एक इंस्टेंटियेटेड सिस्टम पास करें। जेनेरिक क्लास

string typeName = <read type name from somwhere>; 
Type myType = Type.GetType(typeName); 

MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>(); 

जाहिर है, MyGenericClass रूप में वर्णित है:

public class MyGenericClass<T> 
अभी

, संकलक शिकायत है कि 'प्रकार या नाम स्थान' MyType 'नहीं किया जा सका पाया गया। "ऐसा करने का एक तरीका होना चाहिए।

+0

जेनिक्स! = टेम्पलेट्स। सभी जेनेरिक प्रकार चर संकलित समय पर हल होते हैं और रनटाइम पर नहीं। यह उन परिस्थितियों में से एक है जहां 4.0 का 'गतिशील' प्रकार उपयोगी हो सकता है। – Will

+1

@Will - किस तरह से? जेनरिक्स के साथ उपयोग किए जाने पर, वर्तमान सीटीपी के तहत आप अनिवार्य रूप से संस्करणों को कॉल करना समाप्त कर देते हैं (जब तक कि मैं एक चाल नहीं खो रहा हूं ...) –

+0

@MarcGravell आप रन टाइम विधि के लिए 'foo.Method ((गतिशील) myGenericClass) का उपयोग कर सकते हैं एक प्रकार के विधि अधिभार के लिए बाध्यकारी, प्रभावी रूप से सेवा लोकेटर पैटर्न। –

उत्तर

173

आप प्रतिबिंब के बिना ऐसा नहीं कर सकते हैं। हालांकि, आप प्रतिबिंब के साथ कर सकते हैं।

using System; 
using System.Reflection; 

public class Generic<T> 
{ 
    public Generic() 
    { 
     Console.WriteLine("T={0}", typeof(T)); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     string typeName = "System.String"; 
     Type typeArgument = Type.GetType(typeName); 

     Type genericClass = typeof(Generic<>); 
     // MakeGenericType is badly named 
     Type constructedClass = genericClass.MakeGenericType(typeArgument); 

     object created = Activator.CreateInstance(constructedClass); 
    } 
} 

नोट:: यहां एक संपूर्ण उदाहरण है

Type genericClass = typeof(IReadOnlyDictionary<,>); 
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2); 
+0

ठीक है, यह अच्छा है, लेकिन कोई भी बनाई गई विधियों को कॉल करने के बारे में कैसे जाता है? अधिक प्रतिबिंब? –

+3

ठीक है, अगर आप अपने सामान्य प्रकार को गैर-जेनेरिक इंटरफ़ेस को लागू करने से दूर हो सकते हैं, तो आप उस इंटरफ़ेस पर जा सकते हैं। वैकल्पिक रूप से, आप अपनी खुद की जेनेरिक विधि लिख सकते हैं जो सामान्य काम के साथ आप जो भी काम करना चाहते हैं, और प्रतिबिंब के साथ * * कॉल करें। –

+0

(आपको तब मेकजेनरिक टाइप इत्यादि को कॉल नहीं करना पड़ेगा, क्योंकि जेनेरिक प्रकार के उदाहरण का निर्माण सामान्य विधि के अंदर भी किया जाएगा।) –

14

दुर्भाग्य से कोई नहीं है। जेनेरिक तर्कों को संकलित समय पर या तो 1) वैध प्रकार या 2) एक अन्य सामान्य पैरामीटर के रूप में हल किया जाना चाहिए। कोई रास्ता नहीं है बड़े हथौड़े के बिना रनटाइम मूल्यों के आधार पर जेनेरिक उदाहरण बनाने के लिए प्रतिबिंब का उपयोग करने के लिए।

1

कुछ अतिरिक्त के साथ चलाने के लिए कैसे: यदि आपका सामान्य वर्ग कई प्रकार के स्वीकार करता है, यदि आप कॉमा जब तुम प्रकार के नाम को छोड़ देते हैं, उदाहरण के लिए शामिल करना चाहिए कैंची कोड। मान लीजिए आप एक वर्ग

public class Encoder() { 
public void Markdown(IEnumerable<FooContent> contents) { do magic } 
public void Markdown(IEnumerable<BarContent> contents) { do magic2 } 
} 

के समान कार्यावधि में मान लीजिए आप एक FooContent

हैं आप संकलन समय पर बाध्य करने के लिए सक्षम थे है कि आप चाहते थे

var fooContents = new List<FooContent>(fooContent) 
new Encoder().Markdown(fooContents) 

हालांकि आप इसे रनटाइम पर नहीं कर सकते हैं। रनटाइम पर ऐसा करने के लिए आप की तर्ज पर करना होगा:

var listType = typeof(List<>).MakeGenericType(myType); 
var dynamicList = Activator.CreateInstance(listType); 
((IList)dynamicList).Add(fooContent); 

गतिशील विधि कॉल में dynamic के उपयोग आह्वान करने के लिए Markdown(IEnumerable<FooContent> contents)

new Encoder().Markdown((dynamic) dynamicList) 

नोट। रनटाइम dynamicList पर List<FooContent> (अतिरिक्त रूप से IEnumerable<FooContent> भी होगा) क्योंकि गतिशीलता का उपयोग अभी भी दृढ़ता से टाइप की गई भाषा के लिए रूट है, रन टाइम बाइंडर उपयुक्त Markdown विधि का चयन करेगा। यदि कोई सटीक प्रकार का मिलान नहीं है, तो यह ऑब्जेक्ट पैरामीटर विधि की तलाश करेगा और यदि रनटाइम बाइंडर अपवाद से मेल नहीं खाता है तो यह चेतावनी दी जाएगी कि कोई विधि मेल नहीं खाती है।

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

2

मेरी आवश्यकताओं थोड़ा अलग थे, लेकिन उम्मीद है कि किसी की मदद करेंगे। मुझे एक कॉन्फ़िगरेशन से प्रकार पढ़ने की आवश्यकता है और जेनेरिक प्रकार को गतिशील रूप से तत्काल करें।

namespace GenericTest 
{ 
    public class Item 
    { 
    } 
} 

namespace GenericTest 
{ 
    public class GenericClass<T> 
    { 
    } 
} 

अंत में, यहां आप इसे कैसे कहते हैं। Define the type with a backtick

var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest"); 
var a = Activator.CreateInstance(t); 
संबंधित मुद्दे