জেনেরিক ক্লাস বা পদ্ধতির সদস্যের কাছ থেকে টি কীভাবে পাবেন?


674

ধরা যাক আমার কোনও শ্রেণি বা পদ্ধতিতে একটি জেনেরিক সদস্য রয়েছে, তাই:

public class Foo<T>
{
    public List<T> Bar { get; set; }

    public void Baz()
    {
        // get type of T
    }   
}

আমি যখন ক্লাস instantiate, Tহয়ে MyTypeObject1, তাই বর্গ একটি জেনেরিক তালিকা সম্পত্তি রয়েছে: List<MyTypeObject1>। নন-জেনেরিক শ্রেণিতে জেনেরিক পদ্ধতিতে এটি একই প্রযোজ্য:

public class Foo
{
    public void Bar<T>()
    {
        var baz = new List<T>();

        // get type of T
    }
}

আমি জানতে চাই, আমার শ্রেণীর তালিকায় কোন ধরণের অবজেক্ট থাকে। সুতরাং তালিকাবদ্ধ সম্পত্তি বলা হয় Barবা স্থানীয় পরিবর্তনশীল baz, কি ধরণের থাকে T?

আমি করতে পারি না Bar[0].GetType(), কারণ তালিকায় শূন্য উপাদান থাকতে পারে। আমি এটা কিভাবে করবো?

উত্তর:


693

আমি যদি সঠিকভাবে বুঝতে পারি তবে আপনার তালিকার ধারক শ্রেণীর মতোই একই ধরণের প্যারামিটার রয়েছে। যদি এটি হয় তবে:

Type typeParameterType = typeof(T);

আপনি যদি objectটাইপ প্যারামিটার হিসাবে ভাগ্যবান পরিস্থিতিতে থাকেন তবে মার্কের উত্তর দেখুন


4
লোল - হ্যাঁ, খুব সত্য; আমি অনুমান যে ওপি শুধুমাত্র ছিল object, IListবা অনুরূপ - কিন্তু এই খুব ভাল সঠিক উত্তর হতে পারে।
মার্ক গ্র্যাভেল

32
আমি কতটা পাঠযোগ্য typeofতা ভালোবাসি । আপনি যদি টি এর typeof(T)
ধরণটি

2
আমি আসলে টাইপফ (টাইপ) ব্যবহার করেছি এবং এটি দুর্দান্ত কাজ করে।
আন্তন

1
যদিও জেনেরিক প্যারামিটার দিয়ে আপনি টাইপফ () ব্যবহার করতে পারবেন না।
রেয়ানভান

2
@ রেনেভেন অবশ্যই আপনি typeof()জেনেরিক প্যারামিটার ব্যবহার করতে পারেন । আপনার কোনও উদাহরণ আছে যেখানে এটি কাজ করবে না? অথবা আপনি কি ধরণের প্যারামিটার এবং রেফারেন্স গুলিয়ে ফেলছেন?
লুয়ান

520

(নোট: আমি অভিমানী করছি ঠিক এ পর্যন্তই আপনি জানেন objectবা IListবা অনুরূপ, এবং তালিকা রানটাইম এ কোন প্রকার হতে পারে যে)

যদি আপনি জানেন এটি একটি List<T>, তবে:

Type type = abc.GetType().GetGenericArguments()[0];

অন্য বিকল্পটি সূচকের দিকে নজর দেওয়া:

Type type = abc.GetType().GetProperty("Item").PropertyType;

নতুন টাইপআইএনফো ব্যবহার করে:

using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];

1
প্রকার টাইপ করুন = abc.GetType ()। GetGenericArguments () [0]; ==> অ্যারে সূচি সীমার বাইরে ...
প্যাট্রিক দেশজার্ডিনস

28
@ ডাওক: তাহলে এটি কোনও তালিকা নয় <T>
মার্ক গ্র্যাভেল

বাইন্ডিংলিস্ট বা তালিকার জন্য বা <T> ধারণ করে এমন কোনও বস্তুর জন্য কিছু দরকার। আমি একটি কাস্টম বাইন্ডিংলিস্টভিউ <T>
প্যাট্রিক

1
বাইন্ডিংলিস্ট <টি> দিয়ে চেষ্টা করুন, আমাদের বন্ডিংলিস্টভিউ <T> বন্ডিং তালিকা থেকে উত্তরাধিকারী <T> এবং আমি উভয়ই আপনার বিকল্প উভয়ই চেষ্টা করেছি এবং এটি কার্যকর হয় না। আমি হয়ত কিছু ভুল করতে পারি ... তবে আমি মনে করি এই সমাধানটি <T> তালিকার জন্য তবে অন্য ধরণের তালিকার জন্য নয়।
প্যাট্রিক দেশজার্ডিনস

প্রকার টাইপ = abc.GetType ()। গেটপোপার্টি ("আইটেম")। সম্পত্তি সম্পত্তি টাইপ; মাইওবজেক্টের পরিবর্তে বাইন্ডিংলিস্টভিউ <মাইঅবজেক্ট> ফিরিয়ে দিন ...
প্যাট্রিক

49

নিম্নলিখিত এক্সটেনশন পদ্ধতিতে আপনি প্রতিবিম্ব ছাড়াই দূরে সরে যেতে পারেন:

public static Type GetListType<T>(this List<T> _)
{
    return typeof(T);
}

বা আরও সাধারণ:

public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return typeof(T);
}

ব্যবহার:

List<string>        list    = new List<string> { "a", "b", "c" };
IEnumerable<string> strings = list;
IEnumerable<object> objects = list;

Type listType    = list.GetListType();           // string
Type stringsType = strings.GetEnumeratedType();  // string
Type objectsType = objects.GetEnumeratedType();  // BEWARE: object

10
এটি কেবল তখনই কার্যকর যখন আপনি ইতিমধ্যে Tসংকলনের সময়টির ধরণটি জানেন । কোন ক্ষেত্রে, আপনার আসলে কোনও কোডের দরকার নেই।
পুনরাবৃত্তি

'রিটার্ন ডিফল্ট (টি);'
চমত্কার

1
@ রিসার্সিভ: আপনি যদি কোনও বেনামি ধরণের একটি তালিকা নিয়ে কাজ করছেন তবে এটি কার্যকর।
জেজেজে

আমি আপনার উত্তরটি পড়ার আগে ঠিক একই জিনিসটি করেছি তবে আমি আমারItemType
টডডমো বলেছিলাম

31

চেষ্টা

list.GetType().GetGenericArguments()

7
নতুন তালিকা <int> () .গেটটাইপ ()। getGenericArguments () System.Type [1] এখানে
System.Int32

@ রাহোতজ GetGenericArgumentsপদ্ধতিটি একটি অ্যারে অবজেক্ট প্রদান করে Type, যার মধ্যে আপনার তারপরে আপনার প্রয়োজনীয় জেনেরিক ধরণের অবস্থানটি পার্স করতে হবে। যেমন Type<TKey, TValue>: আপনি করতে হবে GetGenericArguments()[0]পেতে TKeyলিখুন GetGenericArguments()[1]পেতে TValueটাইপ
GoldBishop

14

এটা আমার জন্য কাজ। যেখানে মাইলিস্টটি কিছু অজানা ধরণের তালিকা।

IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;

1
আমি একটি ত্রুটি পেয়েছি যে এটির জন্য একটি টাইপ আর্গুমেন্টের প্রয়োজন (যেমন <T>)
জোসেফ হামফ্রে

জোসেফ এবং অন্যান্যরা, ত্রুটি থেকে মুক্তি পেতে এটি সিস্টেম.কলেকশনে রয়েছে।
ব্যবহারকারী 2334883

1
আমার জন্য কেবল দ্বিতীয় লাইনের প্রয়োজন। এ Listইতিমধ্যে একটি বাস্তবায়ন IEnumerable, সুতরাং castালাই কিছু যোগ করবেন বলে মনে হয় না। তবে ধন্যবাদ, এটি একটি ভাল সমাধান।
পাইপড্রিমবম্ব

10

আপনার যদি পুরো টাইপ ভেরিয়েবলের প্রয়োজন হয় না এবং কেবল প্রকারটি পরীক্ষা করতে চান তবে আপনি সহজেই একটি অস্থায়ী ভেরিয়েবল তৈরি করতে পারেন এবং ব্যবহারটি অপারেটর।

T checkType = default(T);

if (checkType is MyClass)
{}

9

আপনি জেনেরিক তালিকার রিটার্ন টাইপের জন্য এটি ব্যবহার করতে পারেন:

public string ListType<T>(T value)
{
    var valueType = value.GetType().GenericTypeArguments[0].FullName;
    return valueType;
}

8

এটি বিবেচনা করুন: আমি একইভাবে 20 টাইপ করা তালিকা রফতানি করতে ব্যবহার করি:

private void Generate<T>()
{
    T item = (T)Activator.CreateInstance(typeof(T));

    ((T)item as DemomigrItemList).Initialize();

    Type type = ((T)item as DemomigrItemList).AsEnumerable().FirstOrDefault().GetType();
    if (type == null) return;
    if (type != typeof(account)) //account is listitem in List<account>
    {
        ((T)item as DemomigrItemList).CreateCSV(type);
    }
}

1
এটি টি কার্যকর হয় না যদি টি প্রকৃত যুক্ত বস্তুর একটি বিমূর্ত সুপারক্লাস হয়। উল্লেখ করার দরকার নেই, ঠিক new T();তেমনই কাজ করবে (T)Activator.CreateInstance(typeof(T));। এটির where T : new()জন্য আপনার ক্লাস / ফাংশন সংজ্ঞা যুক্ত করা দরকার, তবে আপনি যদি বস্তু তৈরি করতে চান তবে তা যাইহোক করা উচিত।
নায়ারগডস

এছাড়াও, আপনি কল করছেন GetTypeFirstOrDefault সম্ভাব্য নাল রেফারেন্স ব্যতিক্রমের ফলে কোনও এন্ট্রিতে করছেন । যদি আপনি নিশ্চিত হন যে এটি কমপক্ষে একটি আইটেম ফিরে আসবে, তবে Firstপরিবর্তে কেন ব্যবহার করবেন না?
ম্যাথিয়াস লাইককেগার্ড লরেঞ্জেন

6

অনুরূপ কিছু সম্পাদন করতে আমি এই এক্সটেনশন পদ্ধতিটি ব্যবহার করি:

public static string GetFriendlyTypeName(this Type t)
{
    var typeName = t.Name.StripStartingWith("`");
    var genericArgs = t.GetGenericArguments();
    if (genericArgs.Length > 0)
    {
        typeName += "<";
        foreach (var genericArg in genericArgs)
        {
            typeName += genericArg.GetFriendlyTypeName() + ", ";
        }
        typeName = typeName.TrimEnd(',', ' ') + ">";
    }
    return typeName;
}

public static string StripStartingWith(this string s, string stripAfter)
{
    if (s == null)
    {
        return null;
    }
    var indexOf = s.IndexOf(stripAfter, StringComparison.Ordinal);
    if (indexOf > -1)
    {
        return s.Substring(0, indexOf);
    }
    return s;
}

আপনি এটি এর মতো ব্যবহার করুন:

[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
    typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
        .ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}

এটি আপনি যা খুঁজছেন তা পুরোপুরি নয়, তবে জড়িত কৌশলগুলি প্রদর্শন করতে এটি সহায়ক।


হাই, আপনার উত্তরের জন্য ধন্যবাদ, আপনি কি "স্ট্রিপস্টার্টিংওয়থ" এর জন্যও এক্সটেনশনটি যুক্ত করতে পারেন?
সিড্রিক আর্নল্ড

1
@ কেড্রিকআর্নল্ড - যুক্ত হয়েছে।
কেন স্মিথ

5

GetGenericArgument()পদ্ধতির উপর আপনার অনুরোধের বেজ টাইপ করুন (যার বর্গ একটি জেনেরিক বর্গ সেট করা হয়েছেmyClass<T> )। অন্যথায়, এটি একটি প্রকার ফিরে আসে [0]

উদাহরণ:

Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();

5

আপনি যে কোনও সংগ্রহের ধরণের থেকে "টি" টাইপ পেতে পারেন যা নিম্নলিখিতটি দিয়ে <<> কার্যকর হয়:

public static Type GetCollectionItemType(Type collectionType)
{
    var types = collectionType.GetInterfaces()
        .Where(x => x.IsGenericType 
            && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        .ToArray();
    // Only support collections that implement IEnumerable<T> once.
    return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
}

মনে রাখবেন যে এটি সংগ্রহের প্রকারগুলিকে সমর্থন করে না যা দু'বার আইনিম্যুয়াল <T> প্রয়োগ করে, যেমন

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }

আমি মনে করি আপনি যদি এটিকে সমর্থন করার প্রয়োজন হয় তবে আপনি কোনও ধরণের অ্যারে ফিরিয়ে দিতে পারেন ...

এছাড়াও, আপনি যদি এই কাজটি প্রচুর পরিমাণে করেন (উদাহরণস্বরূপ একটি লুপে) তবে সংগ্রহের ধরণ অনুযায়ী ফলাফলও ক্যাশে করতে চাইতে পারেন।


1
public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}

1
এটি টাইপটি কোনও তালিকার ওয়াই সাজানোর জিনিস কিনা তা প্রশ্নে সম্বোধন করে, তবে প্রশ্নটি কী জেনেরিক টাইপ পরামিতি এমন একটি ধরণের যা ইতিমধ্যে তালিকা হিসাবে পরিচিত বলে পরিচিত তা নির্ধারণ করতে হবে to
নাথন টগি 6:38

1

3 ডিগ্রাবারের সমাধানটি ব্যবহার করে:

public static T GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return default(T);
}

//and now 

var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();

0

আপনি যদি কোনও সম্পত্তির অন্তর্নিহিত ধরণের জানতে চান তবে এটি ব্যবহার করে দেখুন:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

0

এইভাবে আমি এটি করেছি

internal static Type GetElementType(this Type type)
{
        //use type.GenericTypeArguments if exist 
        if (type.GenericTypeArguments.Any())
         return type.GenericTypeArguments.First();

         return type.GetRuntimeProperty("Item").PropertyType);
}

তারপরে এটিকে কল করুন

var item = Activator.CreateInstance(iListType.GetElementType());

অথবা

var item = Activator.CreateInstance(Bar.GetType().GetElementType());

-9

টাইপ করুন:

type = list.AsEnumerable().SingleOrDefault().GetType();

1
যদি তালিকার ভিতরে এটির বিরুদ্ধে পরীক্ষা করার জন্য কোনও উপাদান না থাকে তবে এটি একটি নালারফেরান ধারণাটি ছুঁড়ে ফেলবে।
রসাইসিয়েড

1
SingleOrDefault()InvalidOperationExceptionদুটি বা ততোধিক উপাদান থাকা অবস্থায়ও ছোঁড়ে ।
ডেভিজেজার

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