2009-07-20 10 views
96

सी # में मेरे पास निम्न ऑब्जेक्ट है:प्रतिबिंब का उपयोग कर जेनेरिक सी # ऑब्जेक्ट को गतिशील रूप से कैसे बनाएं?

public class Item 
{ } 

public class Task<T> 
{ } 

public class TaskA<T> : Task<T> 
{ } 

public class TaskB<T> : Task<T> 
{ } 

मैं सी # प्रतिबिंब ( Activator.CreateInstance) का उपयोग करके गतिशील रूप से टास्क या टास्कब बनाना चाहता हूं। हालांकि मैं हाथ से पहले के प्रकार को नहीं जानता, इसलिए मुझे "नेमस्पेस। टास्क" या "नेमस्पेस। टास्कैब" जैसे स्ट्रिंग के आधार पर गतिशील रूप से टास्क बनाने की आवश्यकता है।

उत्तर

182

यह article और यह simple example देखें। अपनी कक्षाओं के लिए एक ही के त्वरित अनुवाद ...

var d1 = typeof(Task<>); 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

प्रति अपने संपादित: उस मामले के लिए, आप यह कर सकते हैं ...

var d1 = Type.GetType("GenericTest.TaskA`1"); // GenericTest was my namespace, add yours 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

देखने के लिए जहाँ मैं नाम के लिए backtick1 के साथ आया था जेनेरिक वर्ग के, this article देखें।

नोट:

Type type = typeof(IReadOnlyDictionary<,>); 
+0

बैकटिक आवश्यक है, यानी अगर यह ओमेटेड है, तो क्या संकलक मानता है कि यह 1 है? – richard

+7

मेरे ब्लॉग आलेख को जोड़ने के लिए धन्यवाद "सी # .Net" (http://omegacoder.com/?p=38) में "सामान्य उदाहरण" के रूप में एक जेनेरिक क्लास को इंस्टेंट्यूट करने के लिए प्रतिबिंब का उपयोग करना। :-) मुझे खुशी है कि लेख नए जीवन को ढूंढ रहा है। – OmegaMan

+0

मैं 'is' कीवर्ड का उपयोग कर जेनेरिक प्रकार की तुलना कैसे करूं? –

2

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

Task<Item> itsMe = o as Task<Item>; 

या क्या मुझे कुछ याद आ रही है?

+3

आप कुछ भी याद नहीं कर रहे हैं। यह मैं हूं जो सीधे सोच नहीं रहा था। मुझे नशे में नहीं होना चाहिए था कि आखिरी नाइट शराब! – Jeff

6

वास्तव में आप अंतिम पंक्ति लिखने में सक्षम नहीं होंगे।

लेकिन शायद आप इस उद्देश्य को बनाने या बनाने के लिए ऑब्जेक्ट बनाना नहीं चाहते हैं। आप शायद अपने नए बनाए गए उदाहरण पर कुछ विधि कॉल करना चाहते हैं।

फिर आप एक इंटरफेस की तरह कुछ की आवश्यकता होगी:

public interface ITask 
{ 
    void Process(object o); 
} 

public class Task<T> : ITask 
{ 
    void ITask.Process(object o) 
    { 
     if(o is T) // Just to be sure, and maybe throw an exception 
     Process(o as T); 
    } 

    public void Process(T o) { } 
} 

और से कॉल करने की:

Type d1 = Type.GetType("TaskA"); //or "TaskB" 
Type[] typeArgs = { typeof(Item) }; 
Type makeme = d1.MakeGenericType(typeArgs); 
ITask task = Activator.CreateInstance(makeme) as ITask; 

// This can be Item, or any type derived from Item 
task.Process(new Item()); 

किसी भी मामले में, आप स्थिर एक प्रकार आप डॉन 'में ढाला नहीं जा जाएगा पहले से पता नहीं (इस मामले में "makeme")। आईटस्क आपको अपने लक्षित प्रकार तक पहुंचने की अनुमति देता है।

यदि यह वही नहीं है जो आप चाहते हैं, तो आपको शायद इसके साथ हासिल करने की कोशिश में कुछ और विशिष्ट होना चाहिए।

+0

हो ठीक है, सवाल बदल गया है :) –

+0

मेरे पास कार्य में प्रक्रिया() जैसी कुछ है। और मेरे मामले में मुझे वास्तव में आखिरी पंक्ति की परवाह नहीं है जैसा आपने कहा था कि मैं बस कार्य कह रहा हूं। प्रक्रिया() इसलिए आखिरी पंक्ति को कोड करने में सक्षम है या नहीं। – Jeff

1

सुनिश्चित करें कि आप इसे एक अच्छे कारण के लिए कर रहे हैं, निम्न जैसे एक साधारण कार्य स्थिर टाइपिंग की अनुमति देंगे और आपके आईडीई को "संदर्भ खोजें" और रिफैक्टर -> नाम बदलें।

public Task <T> factory (String name) 
{ 
    Task <T> result; 

    if (name.CompareTo ("A") == 0) 
    { 
    result = new TaskA(); 
    } 
    else if (name.CompareTo ("B") == 0) 
    { 
    result = new TaskB(); 
    } 

    return result; 
} 
+0

आप क्यों उपयोग कर रहे हैं .CompareTo? क्यों नहीं == या। (यदि आप अधिक नियंत्रण चाहते हैं)। शायद एक स्विच भी बेहतर होगा। – Zyphrax

+0

मैंने कभी जांच नहीं की है कि सी # संदर्भ तुलना के बजाय == पर एक स्ट्रिंग तुलना करता है। तुलना करें और समानताएं समान रन टाइम दक्षता होनी चाहिए यदि उन्हें सही ढंग से कार्यान्वित किया गया हो। एक स्विच ब्लॉक में एक स्विच ब्लॉक में एक पूर्णांक डालने के समान गति-अप नहीं होगा; यह एक if-else ब्लॉक के लिए संकलित होगा। – clemahieu

1

मुझे पता है कि यह प्रश्न हल हो गया है, लेकिन इसे पढ़ने के किसी और के लाभ के लिए; आप तारों के रूप में शामिल किया प्रकार के सभी है, तो आप एक एक लाइनर के रूप में ऐसा कर सकता है:

IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface); 

जब भी मैं बात इस तरह का किया है, मैं एक अंतरफलक जो मैं का उपयोग करने के बाद कोड चाहते थे मिला है , इसलिए मैंने बनाया गया उदाहरण एक इंटरफेस में डाला है।

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