2012-05-31 16 views
8

मैं इस परिदृश्य के साथ एक सामान्य विधि कॉलिंग:सही व्युत्पन्न प्रकार

मैं तीन श्रेणियां होती हैं, उन्हें A, B और C फोन करते हैं। उनके पास आम बात यह है कि वे एक ही इंटरफ़ेस, ISomeInterface से प्राप्त होते हैं और वे कक्षाएं हैं जो इकाई फ्रेमवर्क का उपयोग करके इकाइयों में मैप की जाती हैं।

मेरे पास एक ऐसी विधि है जिसने इस इंटरफ़ेस को लागू करने वाली वस्तुओं की एक सूची प्राप्त की है, लेकिन ऑब्जेक्ट्स स्वयं A, B या C के उदाहरण होंगे।

विधि खोल इस

public void MyMethod(List<ISomeInterface> entityList) 
{ 
    foreach(var entity in entityList) 
    { 
    ProcessEntity(entity); 
    } 
} 

तरह लग रहा है अब, समस्या ProcessEntity विधि के साथ है। यह एक सामान्य विधि, प्रकार या संस्था के अनुसार डेटाबेस से मिलान तत्वों की तालिका को पुनः प्राप्त करने की जरूरत है, तो यह इस तरह दिखता है:

public void ProcessEntity<T>(T entity) 
{ 
    using(var repository = new DbRepository()) 
    { 
    var set = repository.Set<T>(); 
    ... 
    } 
} 

समस्या यह है कि लाइन var set = repository.Set<T>(); विफल रहता है क्योंकि TISomeInterface है इस मामले में, और वास्तविक प्रकार (A, B या C) नहीं, इसलिए यह एक अपवाद देता है जो दिए गए प्रकार से संबंधित नहीं हो सकता है, जो समझ में आता है।

तो मेरा सवाल यह है कि: मैं सूची के अंदर वस्तु के वास्तविक प्रकार के साथ ProcessEntity को कैसे कॉल कर सकता हूं, न कि इंटरफ़ेसटाइप जो वे लागू करते हैं।

उत्तर

13

प्रोसेसएन्टिटी को इकाई पास करते समय आप dynamic कीवर्ड लागू कर सकते हैं। इस मामले में वास्तविक प्रकार की इकाई रनटाइम पर निर्धारित की जाएगी।

public void MyMethod(List<ISomeInterface> entityList) 
{ 
    foreach(var entity in entityList) 
    { 
    dynamic obj = entity; 
    ProcessEntity(obj); 
    } 
} 
+1

कि चाल किया था इस्तेमाल कर सकते हैं। मैं 'ProcessEntity (obj);' 'ProcessEntity (गतिशील के रूप में obj); ', और यह ठीक काम करता है। गतिशील के लिए एक उपयोग के बारे में पता नहीं था।बहुत बहुत धन्यवाद :) –

+0

@ ØyvindKnobloch-Bråthen yep, मुझे यह रन-टाइम टाइपिफिकेशन बहुत पसंद है –

2

ठीक है, आप एक आगंतुक की तरह चाल करते हैं और निम्नलिखित तरीके का उपयोग कर सकते हैं:

  1. ISomeInterface
  2. में एक विधि Process(EntityProcessor ep) परिभाषित सिर्फ ep.ProcessEntity<A>(this) रूप A में इसे लागू (और उसी तरह B और C)
  3. अपने लूप में ProcessEntity(entity) के बजाय, बस entity.Process(this) पर कॉल करें।

(विधि के नाम शायद नहीं साफ कर रहे हैं, लेकिन आप विचार प्राप्त करना चाहिए)

+0

यह काम करेगा, लेकिन lazyberezovsky का जवाब मेरे लिए बहुत साफ है क्योंकि इसका मतलब है कि मुझे ए, बी में अधिक तर्क डालना नहीं है और सी (और इन प्रकारों में से 20 की तरह अकसर है, 3 नहीं;)) –

+0

@ ओविंद: ठीक है, मेरे समाधान के लिए और अधिक काम की आवश्यकता है, लेकिन यह संकलन समय पर आवश्यक विधि के अस्तित्व की जांच करता है। साथ ही, यह थोड़ा तेज हो सकता है। – Vlad

+0

मैं आपका बिंदु देखता हूं, लेकिन गतिशील का उपयोग करने के लिए आपके पास एक आवश्यक विधि नहीं है, और मैं यह पसंद करूंगा कि कक्षा ए, बी और सी को इस कार्यक्षमता के बारे में कोई जानकारी नहीं है। इसका यह भी अर्थ है कि मुझे इस वर्ग की नई कक्षाओं के लिए अतिरिक्त कार्यक्षमता डालने की याद नहीं है जिसे समान पैटर्न का पालन करना है। –

2

आप प्रतिबिंब का उपयोग सामान्य विधि परिभाषा मिलता है और फिर इसे कॉल करने के लिए कर सकता है, उदाहरण के लिए:

var method = typeof(ClassContainingProcessEntity) 
    .GetMethod(ProcessEntity) 
    .MakeGenericMethod(entity.GetType); 
method.Invoke(this, entity); 

आप टाइप करके विधि को कैश कर सकते हैं, और यदि आप प्रदर्शन महत्वपूर्ण हैं तो आप इसे किसी प्रकार के प्रतिनिधि कारखाने का उपयोग करके रनटाइम पर संकलित कर सकते हैं।

वैकल्पिक रूप से आप Visitor pattern

+0

यूप, दोनों काम करना चाहिए, और अगर मैं यहां कोई बेहतर जवाब नहीं मिला तो मैं प्रतिबिंब मार्ग जाने की सोच रहा था। ऐसा लगता है कि डायनामिक फिक्स्ड यह बहुत साफ है हालांकि। आपके सहयोग के लिए धन्यवाद :) –

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