সেখানে টাইপ পুনরুদ্ধার করতে একটি উপায় T
থেকে IEnumerable<T>
প্রতিফলন মাধ্যমে?
যেমন
আমার একটি পরিবর্তনশীল IEnumerable<Child>
তথ্য আছে; আমি প্রতিবিম্বের মাধ্যমে সন্তানের ধরণটি পুনরুদ্ধার করতে চাই
সেখানে টাইপ পুনরুদ্ধার করতে একটি উপায় T
থেকে IEnumerable<T>
প্রতিফলন মাধ্যমে?
যেমন
আমার একটি পরিবর্তনশীল IEnumerable<Child>
তথ্য আছে; আমি প্রতিবিম্বের মাধ্যমে সন্তানের ধরণটি পুনরুদ্ধার করতে চাই
উত্তর:
IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];
Thusly,
IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);
কপি করে প্রিন্ট System.String
।
এর জন্য এমএসডিএন দেখুন 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()
সরল পরিস্থিতিগুলির বিকল্প যেখানে এটি হয় হয় 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<>
এটি প্রেরণ করা টাইপটি ফিরিয়ে দেবে objects বস্তুর জন্য, ব্যবহার করুন 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)
এখানে আমার অপঠনযোগ্য লিনক ক্যোয়ারী এক্সপ্রেশন সংস্করণটি ..
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
যুক্তি হিসাবে একটি কংক্রিট উদাহরণের পরিবর্তে গ্রহণ করে। যাইহোক, এক্স অজানা প্রতিনিধিত্বকারী হিসাবে , আমি এই ভিডিওটি অপ্রস্তুত হলেও এটি উত্সাহজনক বলে মনে করেছি ..