IEnumerable <T> থেকে টি টাইপ করা


106

সেখানে টাইপ পুনরুদ্ধার করতে একটি উপায় Tথেকে IEnumerable<T>প্রতিফলন মাধ্যমে?

যেমন

আমার একটি পরিবর্তনশীল IEnumerable<Child>তথ্য আছে; আমি প্রতিবিম্বের মাধ্যমে সন্তানের ধরণটি পুনরুদ্ধার করতে চাই


1
কোন প্রসঙ্গে? এই অনুমানযোগ্য <টি> কি? এটি কি কোনও বস্তুর উদাহরণকে আর্গুমেন্ট হিসাবে প্রেরণ করা হয়েছে? অথবা কি?
মেহরদাদ আফশারি

উত্তর:


142
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


বা আরও খারাপ এটির ফলনের সাথে একটি পদ্ধতি লিখুন এবং এই পদ্ধতিটি দিয়ে তৈরি একটি ভেরিয়েবলের উপর গেটটাইপ কল করার চেষ্টা করুন। এটি আপনাকে বলবে যে এটি কোনও জেনেরিক ধরণের ঘটনা নয়। সুতরাং মূলত টির জন্য উদাহরণস্বরূপ ভেরিয়েবলটি দেওয়ার জন্য কোনও সর্বজনীন উপায় নেই IEnumerable <T>
দারিন দিমিত্রভ

1
বা ক্লাস মাইক্লাসের সাথে চেষ্টা করুন: আইনিম্যুয়াল <int> {}} এই শ্রেণীর জেনেরিক ইন্টারফেস নেই।
স্টিফান স্টেইনগার

1
কেন কেউ কখনও জেনেরিক আর্গুমেন্টগুলি পাওয়ার এবং তার সূচক থেকে টাইপটি ধরার জন্য অবলম্বন করবে? এটি কেবল বিপর্যয়ের জন্যই জিজ্ঞাসা করছে, বিশেষত যখন ভাষাটি এমএসপ্রিচের মতো টাইপফ (টি) সমর্থন করে তার উত্তরটিতে, যা জেনেরিক বা পরিচিত ধরণের দ্বারাও ব্যবহার করা যেতে পারে ...
রবার্ট পেটজ

লিনক ক্যোয়ারীগুলি ব্যবহার করার সময় এটি মারাত্মকভাবে ব্যর্থ হয় - হিয়ারস্লেইটইমিউরেবলআইটারের প্রথম জেনেরিক যুক্তিটি নয় । আপনি অন্তর্নিহিত বস্তুর জেনেরিক যুক্তি পেয়ে যাচ্ছেন, ইন্টারফেসটি নয় itself
Pxtl

myEnumerable.GetType ()। getGenericArguments () [0] আপনাকে পুরো নাম সম্পত্তি দেয় যা আপনাকে নামস্পেস.ক্লাসনাম বলে। । আপনি শুধুমাত্র বর্গ নামটি 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;
}

আমার দিন বাঁচিয়েছে আমার ক্ষেত্রে, স্ট্রিংগুলি পরিচালনা করতে আমি পৃথক পৃথক স্টেটমেন্ট যুক্ত করেছি যেহেতু এটি আইনেম্যারেবল <চার> প্রয়োগ করে
এডমন্ড পি চারুম্বীরা

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
কিছু বস্তু একাধিক জেনেরিক আইমুনিউরেবল প্রয়োগ করে।
জেসন

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 () ব্যবহার করতে পারেন। আমি আমার উত্তরটি পরিবর্তন করব।
মূক্ত

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<>এটি প্রেরণ করা টাইপটি ফিরিয়ে দেবে 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;
    }
}

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

এখানে আমার অপঠনযোগ্য লিনক ক্যোয়ারী এক্সপ্রেশন সংস্করণটি ..

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যুক্তি হিসাবে একটি কংক্রিট উদাহরণের পরিবর্তে গ্রহণ করে। যাইহোক, এক্স অজানা প্রতিনিধিত্বকারী হিসাবে , আমি এই ভিডিওটি অপ্রস্তুত হলেও এটি উত্সাহজনক বলে মনে করেছি ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.