वहाँ प्रतिबिंब के माध्यम Tसे प्रकार को पुनः प्राप्त करने का एक तरीका है IEnumerable<T>?
जैसे
मेरे पास एक चर IEnumerable<Child>जानकारी है; मैं प्रतिबिंब के माध्यम से बच्चे के प्रकार को पुनः प्राप्त करना चाहता हूं
वहाँ प्रतिबिंब के माध्यम Tसे प्रकार को पुनः प्राप्त करने का एक तरीका है IEnumerable<T>?
जैसे
मेरे पास एक चर IEnumerable<Child>जानकारी है; मैं प्रतिबिंब के माध्यम से बच्चे के प्रकार को पुनः प्राप्त करना चाहता हूं
जवाबों:
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।
मैं अभी एक विस्तार विधि बनाऊँगा। यह सब कुछ मैं इसे फेंक दिया के साथ काम किया।
public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}
मुझे भी ऐसी ही समस्या का समाधान करना पड़ा था। चयनित उत्तर वास्तविक उदाहरणों के लिए काम करता है। मेरे मामले में मेरे पास केवल एक प्रकार (एक से) था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;
}
Type.GenericTypeArguments- केवल डॉटनेट फ्रेमवर्क संस्करण के लिए> = 4.5। अन्यथा - Type.GetGenericArgumentsइसके बजाय उपयोग करें ।
यदि आप 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);
Type typeपैरामीटर के बजाय एक object objपैरामीटर: तुम सिर्फ स्थान नहीं ले सकता obj.GetType()के साथ typeक्योंकि अगर आप में से गुजरती हैं typeof(IEnumerable<T>)आप कुछ भी नहीं मिलता है। इसे गोल करने के लिए, typeयह देखने के लिए कि क्या यह सामान्य है IEnumerable<>और फिर इसके इंटरफेस हैं , स्वयं का परीक्षण करें।
चर्चा के लिए आपका बहुत-बहुत धन्यवाद। मैंने इसे नीचे दिए गए समाधान के लिए एक आधार के रूप में इस्तेमाल किया, जो उन सभी मामलों के लिए अच्छी तरह से काम करता है जो मेरे लिए रुचि रखते हैं (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()
महज प्रयोग करें typeof(T)
संपादित करें: या .GetType () का उपयोग करें । GetGenericParameter () एक तात्कालिक वस्तु पर यदि आप टी।
सरल स्थितियों के लिए एक विकल्प जहां यह या तो एक होने जा रहा है 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;
}
यह एली अलग्रांति के समाधान पर एक सुधार है कि यह भी काम करेगा जहां 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;
}
}
मुझे पता है कि यह थोड़ा पुराना है, लेकिन मेरा मानना है कि यह विधि टिप्पणियों में बताई गई सभी समस्याओं और चुनौतियों को कवर करेगी। मेरे काम को प्रेरित करने के लिए एली अलग्रांति को श्रेय।
/// <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<>);
}
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
typeof(IEnumerable<Foo>)। इस मामले में पहला सामान्य तर्क लौटाएगा ।GetGenericArguments()[0]typeof(Foo)
यहाँ मेरे अपठित 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तर्क के रूप में एक ठोस उदाहरण के बजाय लेता है । वैसे, एक्स अज्ञात के लिए प्रतिनिधित्व करता है , मुझे यह वीडियो इंस्ट्रेस्टिंग लगा, हालांकि यह अप्रासंगिक है।