2012-02-04 20 views
28

मेरे पास एक सामान्य प्रकार Store<T> है और इस प्रकार का उदाहरण बनाने के लिए Activator का उपयोग करें। अब, एक्टिवेटर का उपयोग करने के बाद, क्या मैं परिणाम object के परिणामस्वरूप ऑब्जेक्ट को तुरंत चालू कर सकता हूं? मैं उस प्रकार को जानता हूं जिसे मैंने जेनेरिक को तुरंत चालू करने के लिए उपयोग किया था। कृपया निम्नलिखित कोड देखें:सामान्य प्रकार का उदाहरण बनाने और इसे उस प्रकार वापस करने के लिए एक्टिवेटर का उपयोग कैसे करें?

class Store<T> where T : IStorable 
{} 

class Beer : IStorable 
{} 

class BeerStore : Store<Beer> 
{} 

Type storeType = someObjectThatImplementsIStorable.GetType(); 
Type classType = typeof(Store<>); 
Type[] typeParams = new Type[] { storeType }; 
Type constructedType = classType.MakeGenericType(typeParams); 

object x = Activator.CreateInstance(constructedType, new object[] { someParameter }); 

मुझे क्या करना चाहते हैं कुछ इस तरह है:

var store = (Store<typeof(objectThatImplementsIStorable)>)x; 

लेकिन यह स्पष्ट कारणों के लिए काम नहीं करता। एक विकल्प के रूप मैंने कोशिश की:

var store = (Store<IStorable>)x; 

जो संभवतः मेरी राय में काम कर सकता है, लेकिन एक InvalidCastException देता है।

मैं Store<T> विधियों को फिर से कैसे प्राप्त करूं जो मुझे पता है कि x ऑब्जेक्ट में हैं?

+0

आप कर सकते हैं 'obvious' कारण और अधिक स्पष्ट? या सिर्फ हमें बताओ कारण क्या है। या आप वास्तव में क्या मतलब है' typeof होना चाहिए ... ' , इसे अपने प्रकार से प्रतिस्थापित नहीं कर रहे हैं? – Snowbear

+1

@nownowear कि कोड का टुकड़ा संकलित नहीं करता है क्योंकि जेनेरिक टी के रूप में उपयोग किए जाने वाले प्रकारों के उदाहरणों की अनुमति नहीं देते हैं। मुझे यह प्रकार पता नहीं है, यह कोई भी वस्तु हो सकती है जो लागू करती है इष्टतम इंटरफ़ेस। – Bazzz

+0

डीबगर सोचने वाला एक्स किस प्रकार का है? क्या यह सही प्रकार है? – CarneyCode

उत्तर

27

के बाद से वास्तविक प्रकार T केवल प्रतिबिंब के माध्यम से आप के लिए उपलब्ध है, तो आप के रूप में अच्छी प्रतिबिंब के माध्यम से Store<T> के तरीकों का उपयोग करने की आवश्यकता होगी:

Type constructedType = classType.MakeGenericType(typeParams); 

object x = Activator.CreateInstance(constructedType, new object[] { someParameter }); 
var method = constructedType.GetMethod("MyMethodTakingT"); 
var res = method.Invoke(x, new object[] {someObjectThatImplementsStorable}); 

संपादित तुम भी एक अतिरिक्त IStore इंटरफ़ेस है कि जेनरिक का उपयोग नहीं करता निर्धारित कर सकते हैं, और बदले IStorable उपयोग करता है:

interface IStore { 
    int CountItems(IStorable item); 
} 
class Store<T> : IStore where T : IStorable { 
    int CountItems(IStorable item) { 
     return count; 
    } 
} 

आपका Store<T> सामान्य रहेगा, लेकिन आप IStore कास्ट कर अपने CountItems तक पहुँच प्राप्त होगा:

var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter }); 
var count = x.CountItems((IStorable)someObjectThatImplementsStorable); 
+0

मुझे डर था कि यह नीचे आ जाएगा। क्या यह अंगूठे का नियम है कि जब मैं वास्तविक प्रकार टी को केवल प्रतिबिंब के माध्यम से जानता हूं कि वास्तविक वस्तु तक पहुंच को प्रतिबिंब के माध्यम से भी जाना है? – Bazzz

+0

@Bazzz हां, अगर केवल कुछ चीज जिसे आप 'someObjectThatImplementsItorable'' के बारे में जानते हैं, यह है कि यह 'वस्तु 'लागू करने वाला' ऑब्जेक्ट 'है, प्रतिबिंब से बचने के लिए आप बहुत कम कर सकते हैं। यदि आपको सामान्य प्रकार 'टी' के रूप में 'someObjectThatImplementsIStorable' मिल रहा था, हालांकि, आप' 'स्टोर भी कर सकते हैं। विधियों के उप-समूह में जेनेरिक से बचने का एक विकल्प होगा (मैं आपको दिखाए जाने के लिए जल्द ही उत्तर अपडेट करूंगा)। – dasblinkenlight

+0

मैं इस तरह से जाऊंगा, मुझे पता है कि मैं यह काम कर सकता हूं, और अन्य विकल्प उपलब्ध नहीं लगते हैं। जवाब के लिए धन्यवाद। यदि आपके पास समय है, तो मैं सबसेट देखना चाहता हूं। बस ब्याज से बाहर और कुछ सीखने के लिए। – Bazzz

3

क्या आप इसे लपेट सकते हैं?

public Store<T> IConstructStore<T>(T item) where T : IStorable 
{ 
return Activator.CreateInstance(typeof(Store<T>), new object[] { someParameter }) as Store<T>; 
} 

या मैं आपको बस इतना करना कोशिश कर रहे हैं याद आ रही है की तरह कुछ?

आईई

class Program 
{ 
    static void Main(string[] args) 
    { 
     Beer b = new Beer(); 
     var beerStore = IConstructStore(b); 
     Console.WriteLine(beerStore.test); 
     Console.WriteLine(beerStore.GetType().ToString()); 
    } 

    public static Store<T> IConstructStore<T>(T item) where T : IStorable 
    { 
     return Activator.CreateInstance(typeof(Store<T>), new object[] { }) as Store<T>; 
    } 
} 

interface IStorable { } 

class Store<T> where T : IStorable 
{ 
    public int test = 1; 
} 

class Beer : IStorable 
{ } 

प्रिंट

1 
ConsoleApp1.Store'1[ConsoleApp1.Beer] 
+0

दिलचस्प, लेकिन फिर? मैं इस विधि को कैसे कॉल करूं? क्या आप नमूना कोड की एक पंक्ति जोड़ सकते हैं? – Bazzz

+0

हाँ जब तक आप इसे किसी भी ऑब्जेक्ट के साथ कॉल करते हैं टी को शामिल किया जाता है, यानी बीयर आइटम = नया बीयर(); var beerStore = IConstructStore (आइटम); BearStore.whatever() ठीक काम करना चाहिए –

+0

'टाइपऑफ (स्टोर ) 'संकलित नहीं करता है, न ही स्टोर ' – Bazzz

2

मेरी राय में सबसे उचित उत्तर यह होगा कि आप इसे इस तरह से नहीं कर सकते हैं।

आप एक इंटरफेस IStorage पेश करने का प्रयास कर सकते हैं और इसे कॉन्वर्सेंट या contravariant बनाने की कोशिश कर सकते हैं (क्या आपने वह विकल्प देखा है?)। यदि यह कोई विकल्प नहीं है, उदाहरण के लिए यदि आपके पास Storage में उपयोग किए जाने वाले इनपुट और आउटपुट जेनेरिक प्रकार दोनों हैं, तो आप जो चाहते हैं उसे लागू करने का कोई तरीका नहीं है।कारण यह है कि Storage<Beer> नहीं सुरक्षित रूप से की वजह से इस मामले को Storage<IStorable> के रूप में इस्तेमाल किया जा सकता है:

Storage<IStorable> store = new Storage<Beer>(); // let's pretend we can do it 
store.Save(new StorableButNotBeer()); // what will happen here? 

आप के लिए ही संभव समाधान के रूप में मैं देख रहा हूँ इस विधि से बाहर ले जाने और कास्टिंग जगह है जहाँ आप जानते में वस्तु कास्ट करने के लिए है सभी सटीक प्रकार:

public void object CreateStore(Type istorableType) 
{ 
    // here is your activator code, but you will have to return an object 
} 

var beerStore = (Store<Beer>)CreateStore(typeof(Beer)); 
+0

आपके सुझाव के लिए धन्यवाद, मेरे पास वास्तव में स्टोर स्टोर में इनपुट और आउटपुट जेनेरिक प्रकार हैं ताकि पथ काम न करे। अन्य सुझाव के अनुसार, ऑब्जेक्ट के उदाहरण के अलावा यह उपलब्ध है कि मैं कहीं भी वास्तविक प्रकार को नहीं जानता हूं। मुझे लगता है कि मैं उस ऑब्जेक्ट पर प्रतिबिंब का उपयोग कर समाप्त करूंगा जो एक्टिवेटर ने बनाया था। समस्या क्यों मौजूद है, इस बारे में अच्छी व्याख्या के लिए +1। – Bazzz

0

मान लें कि कुछ ऑब्जेक्टटैट्स अपूर्ण है MyStorable प्रकार का है।

उदा। MyStorable someObjectThatImplementsIStorable = नया MyStorable(); ... // यहां आपका बाकी कोड।

फिर एक्स स्टोर में नहीं डाला जा सकता है, लेकिन इसे स्टोर में डाला जा सकता है। निम्नलिखित काम करेंगे: (स्टोर) x

ध्यान दें कि हालांकि MyStorable कार्यान्वयन लागू है, स्टोर और स्टोर के बीच कोई संबंध नहीं है। ये दो अलग-अलग वर्ग हैं जो एक-दूसरे से नहीं निकलते हैं।

यू।

+0

आपने दूसरे शब्दों में समस्या का वर्णन करने में कामयाब रहे हैं। :) – Bazzz

+0

आप टी, यानी (स्टोर) एक्स wont संकलन के बिना एक सामान्य प्रकार कास्ट नहीं कर सकते –

0

टी प्रकार (स्टोर typeof का उपयोग न स्टोर