2012-04-13 15 views
5

पर जेनेरिक इंटरफेस के साथ जेनेरिक टाइप बनाएं मैं अब कुछ घंटों के लिए किसी समस्या के माध्यम से काम कर रहा हूं, और मुझे लगता है कि मैं करीब हूं। मैं एक ऐप पर काम कर रहा हूं जहां हमारे पास 50-100 प्रकार हो सकते हैं जो एक ही तरीके से प्रदर्शन करते हैं। तो बजाय 50-100 कक्षाएं बनाने के बजाय, मैं इसे सामान्य करने की कोशिश की है और इस मैं क्या है:रन टाइम

इस आधार वर्ग है:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity 

और इस इंटरफेस है:

public interface IRavenWriter<T> 
{ 
    int ExecutionIntervalInSeconds { get; } 
    void Execute(object stateInfo); 
    void Initialize(int executionIntervalInSeconds, Expression<Func<T, DateTime>> timeOrderByFunc); 
} 

और यह मैं इसे कैसे उपयोग कर रहा हूँ है:

private static void StartWriters() 
{ 
    Assembly assembly = typeof(IDataEntity).Assembly; 
    List<IDataEntity> dataEntities = ReflectionUtility.GetObjectsForAnInterface<IDataEntity>(assembly); 

    foreach (IDataEntity dataEntity in dataEntities) 
    { 
     Type dataEntityType = dataEntity.GetType(); 
     Type ravenWriterType = typeof(RavenWriterBase<>).MakeGenericType(dataEntityType); 

     Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime; 

     // This is where I'm stuck. How do I activate this as RavenWriterBase<T>? 
     var ravenWriter = Activator.CreateInstance(ravenWriterType); 

     //ravenWriter.Initialize(60, func); // I can't do this until I cast. 

     // More functionality here (not part of this issue) 
    } 
} 

मैं ऊपर से इस लाइन पर अटक कर रहा हूँ:

var ravenWriter = Activator.CreateInstance(ravenWriterType); 

यह मेरा सवाल यह है:
मैं उपयोग कर सकते हैं कैसे है कि RavenWriterBase या IRavenWriter के रूप में? कुछ की तरह:

ravenWriter.Initialize(60, func); 

मैं यह कुछ इस तरह की जरूरत है लगता है, लेकिन मैं IRavenWriter < का प्रकार निर्दिष्ट करने की जरूरत है> और मैं इसे अभी तक पता नहीं:

var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>; 

मैं तो ravenWriter पर होवर करें, मैं सफलतापूर्वक मेरी वस्तु है:

enter image description here

लेकिन अब मैं एक सामान्य तरीके से उपयोग करने में सक्षम होने की जरूरत है। मैं उसे कैसे कर सकता हूँ?

अद्यतन:

मैं सिर्फ डायनामिक कीवर्ड का उपयोग कर के बारे में सोचा है, और इस काम करता है:

dynamic ravenWriter = Activator.CreateInstance(ravenWriterType); 
ravenWriter.Initialize(60); 

मैं क्योंकि मैंने महसूस किया कि समारोह प्रत्येक IDataEntity के लिए ही था थोड़ा धोखा दिया तो, प्रारंभिक() को पैरामीटर के रूप में पास करना आवश्यक नहीं था। हालांकि, कम से कम अब मैं कॉल प्रारंभ() कर सकता हूं। लेकिन अब जब फंक एक जैसा है, तो मुझे सामान्य इंटरफ़ेस की आवश्यकता नहीं होनी चाहिए।

+2

जेनिक्स के अनुचित उपयोग की तरह लगता है। जब आप खुद को विभिन्न प्रकारों के आधार पर अलग-अलग तरीकों को चलाने की आवश्यकता महसूस करते हैं, लेकिन प्रकार केवल रनटाइम पर ही ज्ञात होते हैं, तो आप बहुरूपता का उपयोग करना चाहते हैं। जेनिक्स आपको क्या प्राप्त कर रहा है? क्या आप जेनेरिक के बिना पहली जगह में तरीकों को चला सकते हैं, यानी IDataEntity के साथ? – mellamokb

+1

मैं मेलमोकब से सहमत हूं। हालांकि, यदि आप जेनेरिक पर सेट हैं, तो एक रैपर क्लास क्यों न बनाएं जिसे आप गैर-सामान्य रूप से तत्काल कर सकते हैं। रैपर में एक विधि होनी चाहिए जो तर्क के रूप में पारित प्रकार के आधार पर RavenWriterBase का उदाहरण देता है। फिर, रैपर को तुरंत चालू करें और अनुरोध विधि के साथ पैरामीटर के रूप में विधि को कॉल करें। इसके लिए एक बड़े स्विच स्टेटमेंट की आवश्यकता होगी, लेकिन कम से कम 200 अलग-अलग वर्ग नहीं होंगे। – dcow

+2

क्या आप अन्य अभिव्यक्तियां बनाते हैं जो टी के लिए IDataEntity का उपयोग नहीं करते हैं? या टी हमेशा एक आईडीटाइन्टिटी है? और यदि टी हमेशा आईडीटाइन्टिटी है, तो जेनेरिक का उपयोग क्यों करें? –

उत्तर

2

मेरे समाधान होगा:

  • IRavenWriter
  • की एक गैर सामान्य इंटरफ़ेस बनाएँ IRavenWriter
  • से IRavenWriter<T> इनहेरिट बनाओ IRavenWriter
  • में Execute और ExecutionIntervalInSeconds रखें बनाओ IRavenWriterFunc<DateTime> और उपयोग किया है कि आपके लेखक
  • एम में ove InitializeIRavenWriter<T>
  • के एक कारखाने का उपयोग प्रकार और अभिव्यक्ति के अनुसार समारोह आरंभ करने के लिए:

उदाहरण के लिए:

public class MyDateTime 
{ 
    public DateTime This { get; set; } 
} 

public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t) 
{ 
    return() => timeOrderByFunc.Compile()(t); 
} 

और आप का उपयोग करें:

GetFunk<MyDateTime>(x => x.This, new MyDateTime(){This = DateTime.Now}); 
+0

मुझे यकीन नहीं है कि मैं अनुसरण करता हूं। यह मुझे ravenWriter का उपयोग RavenWriterBase <> या IRavenWriter <> के रूप में कैसे करने की अनुमति देता है? –

+0

@BobHorn यह नहीं करता है। आपको वहां 'RavenWriterBase <>' का ज्ञान नहीं हो सकता है। इसके बजाय आपको वहां 'IRavenWriterBase' (गैर-जेनेरिक) का उपयोग करने की आवश्यकता है।इस प्रकार का संकलन-समय ज्ञान वहां मौजूद नहीं है ताकि आप कास्ट नहीं कर सकें। – Aliostad

+0

धन्यवाद। मैंने बस यह दिखाने के लिए अपना प्रश्न संपादित किया कि मैं डायनामिक का उपयोग करके प्रारंभ() को कैसे कॉल कर सकता हूं। मुझे लगता है कि काम करना चाहिए। –

1

यह नहीं है संकलन-समय जेनेरिक टाइप पैरामीटर में रन-टाइम Type को चालू करना वाकई मुश्किल है। dataEntityType साथ

 

interface IRawenWriterFactory 
{ 
    object Create(); 
} 

class RawenWriterFactory<T> : IRawenWriterFactory 
{ 
    public object Create() 
    { 
    Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime; 

    var ravenWriter = new RavenWriterBase<T>(); 
    ravenWriter.Initialize(60, func); 

    return ravenWriter; 
    } 
} 
 

अब बस बनाने RawenWriterFactory आप ravenWriter बना लिया है, जैसे और गैर सामान्य IRavenWriterFactory इंटरफ़ेस के माध्यम से इसका इस्तेमाल करते हैं: बस बनाने/अपने वस्तुओं को प्रारंभ करने के लिए नए इंटरफ़ेस का परिचय।

हालांकि, यदि आप अपना डिज़ाइन बदल देंगे तो सरल समाधान हो सकते हैं। जैसे यदि आप कन्स्ट्रक्टर में प्रारंभिक विधि को चालू करते हैं तो आप func.CreateInstance पैरामीटर के रूप में func को पास करने में सक्षम होंगे और आपको प्रारंभिकरण के लिए जेनेरिक इंटरफ़ेस का उपयोग करने की आवश्यकता नहीं होगी।

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