2009-03-26 9 views
15

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

public class Repository<T> {...} 

और मैं एक तार के साथ कि उदाहरण की जरूरत है ... उदाहरण:

string _sample = "TypeRepository"; 
var _rep = new Repository<sample>(); 

मैं ऐसा कैसे कर सकता है? क्या यह भी संभव है?

धन्यवाद!

+0

ध्यान दें कि आप अपने प्रोग्राम में रिपोजिटरी का उल्लेख नहीं कर सकते हैं, इसलिए _rep के प्रकार को 'ऑब्जेक्ट' या कुछ रेपॉजिटरी के लिए सामान्य इंटरफ़ेस होना चाहिए। –

उत्तर

24

यहाँ मेरी 2 सेंट है।

MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); 
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); 
closedMethod.Invoke(repository, new[] { "Query String" }); 
+0

और मैं रिपोजिटरी विधियों तक कैसे पहुंच सकता हूं? – Paul

+2

वैसे ही जिस तरह से आपने प्रतिबिंब का उपयोग करके रन-टाइम में केवल उस प्रकार के लिए भंडार बनाया है। आप लचीलापन चाहते हैं, आपको इसके लिए भुगतान करना होगा। – alex

+0

क्या आप मुझे दिखा सकते हैं कि यह कैसे करें? धन्यवाद! – Paul

-3

जेनेरिक वर्ग में "टी" एक प्रकार का उदाहरण नहीं है, एक प्रकार का उदाहरण नहीं है। इसलिए यदि आप अपने भंडार स्ट्रिंग वस्तुओं धारण करने के लिए चाहते हैं, तो का उपयोग

var _rep = new Repository<string>(); 
+0

मुझे लगता है कि आपने प्रश्न को गलत समझा है - स्ट्रिंग में एक प्रकार का नाम है। –

16

पहले प्रकार का उपयोग कर Type.GetType(stringContainingTheGenericTypeArgument)

तो एक सामान्य प्रकार प्राप्त करने के लिए typeof(Repository<>).MakeGenericType(theTypeObject) का उपयोग वस्तु मिलता है।

और अंत में Activator.CreateInstance

+0

असली सवाल नहीं है "वह चाहिए"? स्ट्रिंग से जेनेरिक प्रकार से –

+0

? शायद। हालांकि MakeGenericType अक्सर linq प्रदाताओं में उपयोग किया जाता है, और उदाहरण के लिए अन्य अभिव्यक्ति वृक्ष उपभोग कोड।यह एक अच्छा सहायक है, हालांकि हर दिन LOB ऐप्स के लिए यह निश्चित रूप से चिंता करने की बात नहीं है। –

0

का उपयोग यह संभव "की तरह" है। इसमें से क्रमबद्ध करें कि आप इसे कर सकते हैं, लेकिन यह एक हैक का थोड़ा सा है।

आप सामने अपनी कक्षाओं को जानते हैं, एक स्विच बयान का उपयोग करें:

आप 3 विकल्प हैं। मूल रूप से इस तरह:

switch(str){ 
    case "TypeRepository": return new Repository<TypeRepository>; 
} 

ऊपर का एक और अधिक उन्नत रूप के रूप में, आप एक hashtable

var factory = new Dictionary<string, Func<object>>(); 
factory.Add("TypeRepository",() => new Repository<TypeRepository>()); 

var theObject = factory["TypeRepository"]() as Repository<TypeRepository>; 

सबसे बड़ी लचीलेपन के लिए के बजाय एक शब्दकोश का उपयोग कर सकते हैं, आप वर्गों के लिए तार मिलान करने के लिए प्रतिबिंब का उपयोग कर सकते चलने के समय पर। ध्यान रखें कि प्रतिबिंब काफी धीमा है, इसलिए यदि आप इसे किसी भी प्रकार की नियमितता से कर रहे हैं, तो आप इससे बचना चाहते हैं। उदाहरण के तौर पर, यहां Frans Bouma's विधि का उपयोग कर एक है। बस अपने कोड में Repository<> को List<> बदलने के लिए:

public static object MakeList(string typeStr) 
{ 
    var nameSpace = "MyTestApplication" + "."; 

    var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED 
    var listType = typeof(List<>).MakeGenericType(objType); 
    return Activator.CreateInstance(listType); 
} 

var listOfThings = MakeList("MyCoolObject") as List<MyCoolObject>; 

नोट: वहाँ कोई रास्ता नहीं तथ्य यह है कि इन सभी तंत्र लौट object, जिसे फिर आप के बजाय वापस लौटाती सिर्फ दृढ़ता से टाइप किया लौटने के बाद अपने उचित प्रकार से कास्ट करने के लिए है से बचने के लिए है मान।

यह अपरिहार्य है, क्योंकि आप रनटाइम तक सूची के प्रकार को नहीं जानते हैं, और सी # संकलन समय पर चीजों को जानने के आसपास बनाया गया है (यह लोगों का मतलब है जब वे "स्थिर रूप से टाइप की गई प्रोग्रामिंग भाषा" कहते हैं)। यह सी # 4 में कम दर्दनाक होगा, जहां आप dynamic वापस कर पाएंगे, जो आपको कास्टिंग बचाएगा।

+0

यह देखते हुए कि एक स्ट्रिंग का उपयोग करके प्रकार का निर्माण किया जा रहा है, सी # उचित रूप से परिणाम के साथ एक विशिष्ट प्रकार को कैसे जोड़ सकता है? –

0

जेनिक्स उदाहरणों पर नहीं, प्रकारों पर काम करते हैं। आप here पढ़ सकते हैं।

ऐसा लगता है कि आप बस अपने वर्ग कि इच्छित प्रकार में ले जाता है और मूल्य initailizes को एक निर्माता जोड़ने की जरूरत:

public class Foo<T> 
{ 
    private T = default(T); 

    public Foo(T initValue) 
    { 
     _val = T; 
    } 
} 
2

अगर मैं आपके सवाल का सही ढंग से समझ ... तुम क्या करने की कोशिश कर रहे है अपना प्रकार लें (रिपोजिटरी < टी >) और रनटाइम पर उस के विशिष्ट, सामान्य कार्यान्वयन का निर्माण करें?

यदि ऐसा है, तो MakeGenericType पर एक नज़र डालें। आप टाइपऑफ (रिपोजिटरी) और सिस्टम का उपयोग कर सकते हैं। उस ऑब्जेक्ट का टाइप जिसे आप टी के लिए चाहते हैं और इसे इस तरह से बनाएं। एक बार आपके पास टाइप हो जाने के बाद, एक्टिवेटर। क्रिएट इंस्टेंस आपके लिए काम करेगा। टिप्पणी में प्रश्न का उत्तर देना

Type genericType = typeof(Repository<>); 
Type[] typeArgs = { Type.GetType("TypeRepository") }; 
Type repositoryType = genericType.MakeGenericType(typeArgs); 

object repository = Activator.CreateInstance(repositoryType); 

:

1
Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); 
object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

यह Repository<string> का एक उदाहरण बन जाएगा। आप जो भी प्रकार चाहें उसके साथ "System.String" को प्रतिस्थापित कर सकते हैं।

2

यह मानते हुए कि अपने स्ट्रिंग एक प्रकार का नाम रखती है, आप लिख सकते हैं

object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

हालांकि, _rep एक untyped वस्तु हो जाएगा, और आप किसी भी तरह से इसके साथ कुछ करने की आवश्यकता होगी। चूंकि आप नहीं जानते कि सामान्य वर्ग किस प्रकार संकलित समय पर है, वहां कोई भी प्रकार नहीं है जिसे आपने इसे डाला है। (जब तक रिपोजिटरी गैर-जेनेरिक वर्ग प्राप्त नहीं करता है या गैर-जेनेरिक इंटरफ़ेस लागू करता है)

आप रिपोजिटरी के लिए गैर-जेनेरिक बेस क्लास बनाकर और ऑब्जेक्ट को कास्टिंग करके इसे हल कर सकते हैं।

हालांकि, आपकी स्थिति के आधार पर, शायद आप Repository एक गैर-सामान्य वर्ग बनाना चाहते हैं।

यदि Repository एक कक्षा है जिसमें अन्य कक्षाएं हैं, तो यह संभवतः गैर-सामान्य बनाने के लिए सबसे अच्छा है। आप इसके कन्स्ट्रक्टर को Type ऑब्जेक्ट ले सकते हैं, और फिर यह सुनिश्चित करने के लिए कि आप सही प्रकार के हैं, प्रत्येक ऑब्जेक्ट पर Type.IsInstanceOfType पर कॉल करें।

यदि रिपोजिटरी चीजों का एक वर्गीकृत संग्रह है, तो यह संभवतः गैर-सामान्य बनाने के लिए सबसे अच्छा है, और इसके निर्माता को string category लेना संभव है।

यदि आप अधिक विशिष्ट सलाह चाहते हैं, तो कृपया अपनी स्थिति के बारे में अधिक जानकारी पोस्ट करें।

+0

मेरे भंडार: सार्वजनिक वर्ग भंडार : RepositoryWithTypedId , IRepository {} सार्वजनिक वर्ग RepositoryWithTypedId: IRepositoryWithTypedId और मुझे लगता है कि implementantion बदल नहीं कर सकते ... तो यह असंभव है? – Paul

+0

ऊपर लिखा गया कोड की रेखा का उपयोग करके यह संभव है, लेकिन इसके साथ कुछ भी करना मुश्किल होगा। आप ऐसा करने का प्रयास क्यों कर रहे हैं, और आप '_rep' के साथ क्या कर रहे हैं? – SLaks

+0

मेरा _rep एक डीएओ (डेटा एक्सेस ऑब्जेक्ट) है ... – Paul

3

यह dynamic कीवर्ड C# 4.0 में आने वाला एक काम है।

यहां कुछ अच्छे हैक्स हैं जो आपको अपने ऑब्जेक्ट का एक उदाहरण प्राप्त करेंगे, लेकिन इससे कोई फर्क नहीं पड़ता कि सी # के वर्तमान संस्करण में केवल यह पता होगा कि इसमें object है, और यह किसी ऑब्जेक्ट के साथ स्वयं नहीं कर सकता है क्योंकि वर्तमान सी # देर से बाध्यकारी का समर्थन नहीं करता है। आपको कम से कम किसी ज्ञात प्रकार के साथ कुछ भी करने के लिए इसे सक्षम करने में सक्षम होना चाहिए। आखिरकार, आपको को संकलित समय पर टाइप करने की आवश्यकता है या आप भाग्य से बाहर हैं।

अब, यदि आप कुछ ज्ञात इंटरफेस को लागू करने के प्रकारों के लिए अपनी रिपोजिटरी क्लास को बाधित कर सकते हैं, तो आप एक बेहतर आकार में हैं।

+0

तो, मेरे पास मेरी समस्या का कोई समाधान नहीं है ... – Paul

+0

नहीं, और मेरा मुद्दा यह है कि आपको वह नहीं मिलेगा जो वास्तव में सी # 4 आने से पहले काम करता है जब तक कि आप अपने आर्किटेक्चर को फिर से सोच सकें। –

+2

यदि आप इन रिपोजिटरी ऑब्जेक्ट्स के साथ जो करना चाहते हैं, साझा करते हैं, तो हम बेहतर तरीके से काम करने वाले डिज़ाइन के साथ आपकी सहायता कर सकते हैं। –

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