2011-06-13 16 views
5

है तो किसी प्रकार के ऑब्जेक्ट के माध्यम से मैं गणना कैसे कर सकता हूं यह व्याख्या करना थोड़ा मुश्किल है। तो यहाँ यह जाता है।जब मैं एक आईनेमरेबल

public T FooBar<T>(Func<T> function) 
{ 
    T returnData = function(); 

    // want to iterate through returnData to do something to it 

    return returnData; 
} 

तो returnData (टी) एक IEnumerable सूची है, तो मैं returnData के माध्यम से गणना करने में प्रतिबिंब का उपयोग कर उसकी सामग्री को संशोधित करने के लिए करना चाहते हैं:

मैं इस तरह एक समारोह है। लेकिन मैं ऐसा करने में सक्षम नहीं लग सकता। जब मैं एक गणनीय प्रकार के returnData कास्ट करने के लिए प्रयास करते हैं, मैं एक अपवाद प्राप्त करें:

प्रकार

'System.Collections.Generic.List`1 [कारें]'

की वस्तु कास्ट करने में असमर्थ

'सिस्टम.कोलेक्शन। जेनरिक.लिस्ट`1 [सिस्टम.ऑब्जेक्ट]' टाइप करने के लिए।

मुझे नहीं पता कि वापसी का प्रकार 'कारों' की एक सूची होगी, उदाहरण के लिए समय से पहले, केवल रन टाइम पर। तो मुझे प्रतिबिंब का उपयोग करके जांचना होगा यदि यह एक सूची है, और फिर इसे कास्ट करने का प्रयास करें ताकि मैं इसके माध्यम से गणना कर सकूं।

जब तक कि मैं इसके बारे में गलत तरीके से नहीं जा रहा हूं। के माध्यम से मैं T प्रकार का उपयोग कैसे कर सकता हूं?

उत्तर

4
if (returnData is System.Collections.IEnumerable) 
{ 
    foreach (object o in (System.Collections.IEnumerable)returnData) 
    { 
     // Do something. 
    } 
} 

वास्तव में, हालांकि, क्यों इस तरह एक अतिरिक्त अधिभार नहीं:

public T FooBar<T>(Func<IEnumerable<T>> function) 
+0

यहाँ मांस और आलू है मैंने ओवरलोड विचार के बारे में सोचा नहीं है। मैं एक बार इसका प्रयास करूँगा। – 7wp

6

एक दृष्टिकोण T पर एक प्रकार बाधा जोड़ने के लिए है, लेकिन यह आदर्श नहीं है:

public T FooBar<T>(Func<T> function) where T : IEnumerable 
{ 
    // T is not strongly typed for the enumerated item 

यदि आपने अपनी विधि को थोड़ा बदल दिया है (wrt T):

public IEnumerable<T> FooBar<T>(Func<IEnumerable<T>> function) 

फिर आपके पास वास्तविक वस्तु को स्वीकार करने के अतिरिक्त बोनस के साथ वास्तविक आइटम पर मजबूत टाइपिंग है।


तो मैं अपने प्रश्न का एक दूसरा पढ़ने से देखा, वहाँ क्या T अपने चर returnData के लिए इसका मतलब के बारे में कुछ भ्रम की स्थिति है। ऐसे मामले में जहां FooBar()List<Car> पारित किया गया है, TList<Car> है, और वास्तव में List<> के जेनेरिक प्रकार विनिर्देश के साथ कोई संबंध नहीं है। आप इसे List<U> के रूप में सोच सकते हैं जहां U कुछ अन्य, अज्ञात प्रकार है।

रनटाइम पर U पर जाने के लिए कोई आसान तरीका नहीं होगा क्योंकि यह T के अंदर, छिपाने के लिए है। आप ओवरलोडिंग का उपयोग कर सकते हैं क्योंकि कुछ अन्य उत्तरदाताओं की सिफारिश है, और एक गैर-IEnumerable<U> विधि प्रदान करें और एक Func<IEnumerable<T>> प्रकार के तर्क लेता है।

शायद FooBar<T> के लक्ष्य के बारे में कुछ और विवरण के साथ हम कुछ और विशिष्ट सिफारिशें कर सकते हैं।

2

क्या आपने IEnumerable<T> के बजाय IEnumerable पर कास्टिंग टाइप करने का प्रयास किया है? IEnumerable के साथ आप अभी भी इसे foreach लूप में उपयोग कर सकते हैं। चर प्रत्येक आइटम में जाना होगा प्रकार object यानी .:

foreach(object item in (IEnumerable)T){...} 

आप पहले की जाँच करनी चाहिए लगता है कि टी लागू करता IEnumerable होने के लिए की जानी चाहिए।

1

यहां समस्या आईनेमरेबल और टी की आईनेमरेबल समान नहीं है ... लेकिन आप अपने कोड में इसके लिए अंतर और खाता देख सकते हैं। ध्यान दें कि टी के IENumerable आईनेमरेबल को विरासत में लेता है, ताकि आप गैर-जेनेरिक संस्करण के अंदर जेनेरिक संस्करण के लिए चेक को लपेट सकें।

मेरे द्वारा लिखे गए एक छोटे से परीक्षण में मेरे लिए निम्नलिखित काम किया - मुझे उम्मीद है कि आपको जो चाहिए वह करने के लिए यह पर्याप्त है।

class FooBarOfT 
{ 
    public T FooBar<T>(Func<T> function) 
    { 
     T returnData = function(); 

     //Want to iterate through returnData to do something to it. 
     if (returnData is IEnumerable) 
     { 
      // get generic type argument 
      var returnDataType = returnData.GetType(); 

      if (returnDataType.IsGenericType) 
      { 
       // this is a System.Collections.Generic.IEnumerable<T> -- get the generic type argument to loop through it 
       Type genericArgument = returnDataType.GetGenericArguments()[0]; 

       var genericEnumerator = 
        typeof(System.Collections.Generic.IEnumerable<>) 
         .MakeGenericType(genericArgument) 
         .GetMethod("GetEnumerator") 
         .Invoke(returnData, null); 

       IEnumerator enm = genericEnumerator as IEnumerator; 
       while (enm.MoveNext()) 
       { 
        var item = enm.Current; 
        Console.WriteLine(string.Format("Type : {0}", item.GetType().Name)); 
       } 

      } 
      else 
      { 
       // this is an System.Collections.IEnumerable (not generic) 
       foreach (var obj in (returnData as IEnumerable)) 
       { 
        // do something with your object 
       } 
      } 
     } 

     return returnData; 
    } 
} 

मैं भी कुछ समर्थन परीक्षण कक्षाओं की स्थापना:

class Foo 
{ 
    private string _fooText; 

    public Foo(string fooText) 
    { 
     _fooText = fooText; 
    } 
    public string Execute() 
    { 
     return string.Format("executed! with {0} !", _fooText); 
    } 
} 

class Bar 
{ 
    public string BarContent { get; set; } 
} 

और कुछ परीक्षण चलाने के लिए एक छोटी सी सांत्वना अनुप्रयोग:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // tests 
     Func<string> stringFunc =() => 
      "hello!"; 

     Func<List<Foo>> listFooFunc =() => 
      new List<Foo> 
      { 
       new Foo("Hello!"), 
       new Foo("World!") 
      }; 

     Func<IEnumerable> ienumerableFooFunc =() => 
      new Hashtable 
      { 
       { "ItemOne", "Foo" }, 
       { "ItemTwo", "Bar" } 
      }; 


     var fooBarOfT = new FooBarOfT(); 

     fooBarOfT.FooBar(stringFunc); 
     fooBarOfT.FooBar(listFooFunc); 
     fooBarOfT.FooBar(ienumerableFooFunc); 

     Console.ReadKey(); 
    } 
} 
संबंधित मुद्दे