IEnumerable <T> से टाइप T प्राप्त करना


106

वहाँ प्रतिबिंब के माध्यम Tसे प्रकार को पुनः प्राप्त करने का एक तरीका है IEnumerable<T>?

जैसे

मेरे पास एक चर IEnumerable<Child>जानकारी है; मैं प्रतिबिंब के माध्यम से बच्चे के प्रकार को पुनः प्राप्त करना चाहता हूं


1
किस संदर्भ में? यह IEnumerable <T> क्या है? क्या यह एक तर्क के रूप में भेजा गया एक वस्तु उदाहरण है? और क्या?
मेहरदाद अफश्री

जवाबों:


142
IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0]; 

इसके अतिरिक्त,

IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);

प्रिंट करता है System.String

देखें MSDN के लिएType.GetGenericArguments

संपादित करें: मेरा मानना ​​है कि यह टिप्पणियों में चिंताओं को संबोधित करेगा:

// returns an enumeration of T where o : IEnumerable<T>
public IEnumerable<Type> GetGenericIEnumerables(object o) {
    return o.GetType()
            .GetInterfaces()
            .Where(t => t.IsGenericType
                && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            .Select(t => t.GetGenericArguments()[0]);
}

कुछ ऑब्जेक्ट एक से अधिक जेनेरिक लागू करते हैं, IEnumerableइसलिए उनमें से एक एन्यूमरेशन वापस करना आवश्यक है।

संपादित करें: हालांकि, मुझे कहना होगा, एक वर्ग के लिए एक IEnumerable<T>से अधिक के लिए लागू करना एक भयानक विचार है T


या इससे भी बदतर उपज रिटर्न के साथ एक विधि लिखें और इस विधि के साथ बनाए गए एक चर पर गेट टाइप को कॉल करने का प्रयास करें। यह आपको बताएगा कि यह एक सामान्य प्रकार की घटना नहीं है। तो मूल रूप से T को प्राप्त करने का कोई सार्वभौमिक तरीका नहीं है I एक प्रकार का उदाहरण दिया गया है IEnumerable <T>
डारिन दिमित्रोव

1
या वर्ग MyClass के साथ प्रयास करें: IEnumerable <int> {}। इस वर्ग में एक सामान्य इंटरफ़ेस नहीं है।
स्टीफन स्टाइनगर

1
कोई भी कभी भी जेनेरिक दलीलें पाने और फिर इसके इंडेक्सर से टाइप हथियाने का सहारा क्यों लेगा? यह सिर्फ आपदा के लिए पूछ रहा है, खासकर जब भाषा टाइपोफ़ (टी) का समर्थन करती है जैसे @amsprich अपने उत्तर में बताती है, जिसका उपयोग या तो एक सामान्य या एक ज्ञात प्रकार के साथ किया जा सकता है ...
रॉबर्ट पेट्ज

यह लिनियर प्रश्नों के साथ प्रयोग करने पर बुरी तरह से विफल हो जाता है - एक WhereSelectEnumerableIterator का पहला सामान्य तर्क नहीं है । आपको अंतर्निहित ऑब्जेक्ट का सामान्य तर्क मिल रहा है, न कि इंटरफ़ेस।
Pxtl

myEnumerable.GetType ()। GetGenericArguments () [0] आपको FullName प्रॉपर्टी देता है जो आपको namespace.classname बताता है। यदि आप केवल क्लास के नाम की तलाश कर रहे हैं तो myEnumerable.GetType () GetGenericArguments () [0] .Name
user5534263

38

मैं अभी एक विस्तार विधि बनाऊँगा। यह सब कुछ मैं इसे फेंक दिया के साथ काम किया।

public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
    return typeof(T);
}

6
यदि आपका संकलन समय संदर्भ केवल ऑब्जेक्ट प्रकार का है तो यह काम नहीं करेगा।
स्टिजेन वान एंटवर्पेन

27

मुझे भी ऐसी ही समस्या का समाधान करना पड़ा था। चयनित उत्तर वास्तविक उदाहरणों के लिए काम करता है। मेरे मामले में मेरे पास केवल एक प्रकार (एक से) थाPropertyInfo ) ।

चयनित उत्तर विफल हो जाता है जब प्रकार स्वयं का typeof(IEnumerable<T>)कार्यान्वयन नहीं होता है IEnumerable<T>

इस मामले के लिए निम्नलिखित काम करता है:

public static Type GetAnyElementType(Type type)
{
   // Type is Array
   // short-circuit if you expect lots of arrays 
   if (type.IsArray)
      return type.GetElementType();

   // type is IEnumerable<T>;
   if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IEnumerable<>))
      return type.GetGenericArguments()[0];

   // type implements/extends IEnumerable<T>;
   var enumType = type.GetInterfaces()
                           .Where(t => t.IsGenericType && 
                                  t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                           .Select(t => t.GenericTypeArguments[0]).FirstOrDefault();
   return enumType ?? type;
}

मेरा दिन बचाया। मेरे मामले के लिए, मैंने एक अलग जोड़ा अगर स्टेटमेंट को संभालने के लिए स्ट्रिंग्स को हैंडल किया जाए क्योंकि यह IEnumerable <char>
एडमंड पी चारुम्बिरा

Type.GenericTypeArguments- केवल डॉटनेट फ्रेमवर्क संस्करण के लिए> = 4.5। अन्यथा - Type.GetGenericArgumentsइसके बजाय उपयोग करें ।
Кее Кто सेप्ट

20

यदि आप IEnumerable<T>(जेनरिक के माध्यम से) जानते हैं , तो बस typeof(T)काम करना चाहिए। अन्यथा (के लिए object, या गैर-सामान्य IEnumerable), लागू किए गए इंटरफेस की जाँच करें:

        object obj = new string[] { "abc", "def" };
        Type type = null;
        foreach (Type iType in obj.GetType().GetInterfaces())
        {
            if (iType.IsGenericType && iType.GetGenericTypeDefinition()
                == typeof(IEnumerable<>))
            {
                type = iType.GetGenericArguments()[0];
                break;
            }
        }
        if (type != null) Console.WriteLine(type);

3
कुछ ऑब्जेक्ट एक से अधिक सामान्य IEnumerable को कार्यान्वित करते हैं।
जसन

5
@ जैसन - और उन मामलों में, "टी खोजें" का सवाल पहले से ही एक संदिग्ध सवाल है; मैं उस बारे में कुछ नहीं कर सकता ...
मार्क ग्रेवेल

एक साथ इस का उपयोग करने की कोशिश कर किसी के लिए भी एक छोटा सा पकड़ लिया Type typeपैरामीटर के बजाय एक object objपैरामीटर: तुम सिर्फ स्थान नहीं ले सकता obj.GetType()के साथ typeक्योंकि अगर आप में से गुजरती हैं typeof(IEnumerable<T>)आप कुछ भी नहीं मिलता है। इसे गोल करने के लिए, typeयह देखने के लिए कि क्या यह सामान्य है IEnumerable<>और फिर इसके इंटरफेस हैं , स्वयं का परीक्षण करें।
इयान मर्सर

8

चर्चा के लिए आपका बहुत-बहुत धन्यवाद। मैंने इसे नीचे दिए गए समाधान के लिए एक आधार के रूप में इस्तेमाल किया, जो उन सभी मामलों के लिए अच्छी तरह से काम करता है जो मेरे लिए रुचि रखते हैं (IEnumerable, व्युत्पन्न वर्ग, आदि)। सोचा था कि मुझे यहाँ साझा करना चाहिए अगर किसी को इसकी आवश्यकता है:

  Type GetItemType(object someCollection)
  {
    var type = someCollection.GetType();
    var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
    return ienum != null
      ? ienum.GetGenericArguments()[0]
      : null;
  }

यहाँ एक लाइनर है जो अशक्त सशर्त ऑपरेटर का उपयोग करके यह सब करता है: someCollection.GetType().GetInterface(typeof(IEnumerable<>).Name)?.GetGenericArguments()?.FirstOrDefault()
मास डॉट नेट

2

महज प्रयोग करें typeof(T)

संपादित करें: या .GetType () का उपयोग करें । GetGenericParameter () एक तात्कालिक वस्तु पर यदि आप टी।


आपके पास हमेशा टी।
जेसन नहीं है

सच है, जिस स्थिति में आप उपयोग कर सकते हैं ।GetType ()। मैं अपना उत्तर संशोधित करूंगा।
लगाम

2

सरल स्थितियों के लिए एक विकल्प जहां यह या तो एक होने जा रहा है IEnumerable<T> या Tके GenericTypeArgumentsबजाय नोट का उपयोग करें GetGenericArguments()

Type inputType = o.GetType();
Type genericType;
if ((inputType.Name.StartsWith("IEnumerable"))
    && ((genericType = inputType.GenericTypeArguments.FirstOrDefault()) != null)) {

    return genericType;
} else {
    return inputType;
}

1

यह एली अलग्रांति के समाधान पर एक सुधार है कि यह भी काम करेगा जहां IEnumerable<> विरासत के पेड़ में किसी भी स्तर पर प्रकार ।

यह समाधान किसी भी प्रकार से तत्व प्रकार प्राप्त करेगा Type। यदि प्रकार कोई नहीं है IEnumerable<>, तो यह ऑब्जेक्ट में उपयोग किए गए प्रकार को वापस कर देगा GetType। प्रकारों के लिए, उपयोग करें typeof, फिर परिणाम पर इस एक्सटेंशन विधि को कॉल करें।

public static Type GetGenericElementType(this Type type)
{
    // Short-circuit for Array types
    if (typeof(Array).IsAssignableFrom(type))
    {
        return type.GetElementType();
    }

    while (true)
    {
        // Type is IEnumerable<T>
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            return type.GetGenericArguments().First();
        }

        // Type implements/extends IEnumerable<T>
        Type elementType = (from subType in type.GetInterfaces()
            let retType = subType.GetGenericElementType()
            where retType != subType
            select retType).FirstOrDefault();

        if (elementType != null)
        {
            return elementType;
        }

        if (type.BaseType == null)
        {
            return type;
        }

        type = type.BaseType;
    }
}

1

मुझे पता है कि यह थोड़ा पुराना है, लेकिन मेरा मानना ​​है कि यह विधि टिप्पणियों में बताई गई सभी समस्याओं और चुनौतियों को कवर करेगी। मेरे काम को प्रेरित करने के लिए एली अलग्रांति को श्रेय।

/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
   if (type.IsArray)
      return type.GetElementType();

   // type is IEnumerable<T>;
   if (ImplIEnumT(type))
      return type.GetGenericArguments().First();

   // type implements/extends IEnumerable<T>;
   var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
   if (enumType != null)
      return enumType;

   // type is IEnumerable
   if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
      return typeof(object);

   return null;

   bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
   bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}

1
public static Type GetInnerGenericType(this Type type)
{
  // Attempt to get the inner generic type
  Type innerType = type.GetGenericArguments().FirstOrDefault();

  // Recursively call this function until no inner type is found
  return innerType is null ? type : innerType.GetInnerGenericType();
}

यह एक पुनरावर्ती कार्य है जो सामान्य प्रकार की सूची में पहले गहराई तक जाएगा, जब तक कि यह कोई आंतरिक सामान्य प्रकार के साथ एक ठोस प्रकार की परिभाषा प्राप्त न करे।

मैंने इस विधि का परीक्षण इस प्रकार किया है: ICollection<IEnumerable<ICollection<ICollection<IEnumerable<IList<ICollection<IEnumerable<IActionResult>>>>>>>>

जो लौट जाना चाहिए IActionResult



0

ऐसा मैं आमतौर पर करता हूं (विस्तार विधि के माध्यम से):

public static Type GetIEnumerableUnderlyingType<T>(this T iEnumerable)
    {
        return typeof(T).GetTypeInfo().GetGenericArguments()[(typeof(T)).GetTypeInfo().GetGenericArguments().Length - 1];
    }

0

यहाँ मेरे अपठित Linq क्वेरी अभिव्यक्ति संस्करण है ..

public static Type GetEnumerableType(this Type t) {
    return !typeof(IEnumerable).IsAssignableFrom(t) ? null : (
    from it in (new[] { t }).Concat(t.GetInterfaces())
    where it.IsGenericType
    where typeof(IEnumerable<>)==it.GetGenericTypeDefinition()
    from x in it.GetGenericArguments() // x represents the unknown
    let b = it.IsConstructedGenericType // b stand for boolean
    select b ? x : x.BaseType).FirstOrDefault()??typeof(object);
}

ध्यान दें कि विधि गैर-जेनेरिक IEnumerableको भी ध्यान में रखती है , objectइस मामले में वापस आती है, क्योंकि यह Typeतर्क के रूप में एक ठोस उदाहरण के बजाय लेता है । वैसे, एक्स अज्ञात के लिए प्रतिनिधित्व करता है , मुझे यह वीडियो इंस्ट्रेस्टिंग लगा, हालांकि यह अप्रासंगिक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.