2009-02-17 5 views
515

Sınıfta veya yöntemde genel bir üye olduğumu varsayalım:Genel bir sınıf veya yöntem üyesinden T türünü nasıl alabilirim?

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

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

Sınıfı hazırladığımda, TMyTypeObject1 olur, böylece sınıfın genel bir liste özelliği vardır: List<MyTypeObject1>. Aynısı, jenerik olmayan bir sınıftaki genel bir yöntem için de geçerlidir:

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

     // get type of T 
    } 
} 

Bilmek istiyorum, sınıfımın listesi ne tür nesneler içeriyor. Yani Bar veya baz yerel değişken olarak adlandırılan liste özelliği ne tür T içeriyor?

Bar[0].GetType() yapamıyorum çünkü liste sıfır öğe içerebilir. Nasıl yapabilirim?

cevap

514

deneyin. Bu durumda o zaman, ise: Eğer bir tip parametresi olarak object sahip şanslı durumda ise

Type typeParameterType = typeof(T); 

, Marc's answer bakın.

+4

Lol olarak giriş - Evet, çok doğru; OP'nin sadece “object”, “IList” veya benzeri olduğunu varsaydım, ama bu doğru cevap olabilir. –

+13

"typeof" in ne kadar okunabilir olduğunu seviyorum. Eğer T türünü bilmek istiyorsanız, sadece 'typeof (T) 'kullanın :) :) – demoncodemonkey

+1

Ben sadece typeof (Type) kullanıyorum ve harika çalışıyor. – Anton

442

(not: Ben tüm bildiklerini object veya IList veya benzer olduğunu tahmin ediyorum ve liste zamanında her tür olabileceğini) sonra, bir List<T> olduğunu biliyorsanız

:

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

yeni typeinfo kullanma::

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

Başka bir seçenek dizinleyicisi bakmaktır

Doğru anladıysam,
using System.Reflection; 
// ... 
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0]; 
+1

Tip türü gibi diyoruz nasıl 0]; ==> Sınır dışı dizi dizini ... –

+22

@Daok: o zaman bir Liste yok

+0

BindingList veya Liste veya tutulan herhangi bir nesne için bir şeye ihtiyacınız var. Ne yapıyorum özel bir BindingListView kullanın

26

Listenizi konteyner sınıfının kendisiyle aynı tip parametresi vardır,

list.GetType().GetGenericArguments() 
+0

Bu çalışmıyor ... GetGenericArguments döndürür System.Type [0] –

+5

yeni Liste () .GetType(). System.Type [1] System.Int32 ile giriş – Rauhotz

-9

Tür:

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

Bu, listede test edilmemesi için öğenin bir öğesi yoksa bir NullReferenceException atar. – rossisdead

+1

'SingleOrDefault()' ayrıca iki veya daha fazla öğe olduğunda InvalidOperationException öğesini atar. – devgeezer

+0

Bu yanıt, \ @rossisdead ve \ @devgeezer tarafından doğru bir şekilde işaret edildiği gibi yanlış. – Oliver

9

bu düşünün: Ben aynı şekilde 20 daktilo liste ihracat kullanmak:

GetGenericArgument() yöntemi örneğinin Temel Türü ayarlanacak olan
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

T, gerçek eklenen nesnelerin soyut bir üst sınıfı ise, bu işe yaramaz. Sadece yeni T(); '(T) Activator.CreateInstance (typeof (T));' ile aynı şeyi yapar. Sınıf/işlev tanımına T: new() 'ifadesini eklemenizi gerektirir, ancak nesneleri yapmak için _want_ olursa, yine de yapılması gerekir. – Nyerguds

+0

Ayrıca, bir "FirstOrDefault" girdisinde "GetType" girdisini çağırarak potansiyel bir boş başvuru istisnasıyla karşılaşıyorsunuz. En az bir öğe döndüreceğinden eminseniz, bunun yerine neden "İlk" kullanılmaz? –

5

(sınıfı, genel bir sınıf olan myClass<T>'dur). Benim için bir iş

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

: Aksi takdirde, bir tür [0]

Örnek döndürür. MyList’in bilinmeyen türden bir liste olduğu yer.Eğer yansıması olmadan kurtulmak aşağıdaki uzatma yöntemi ile

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

Bir hata türünün (örn. '') –

+0

Joseph ve diğerleri için System.Collections dosyasındaki hatadan kurtulmak için bir hata alıyorum. – user2334883

+1

Sadece ikinci hat benim için gerekli. '' '' '' IEnumerable'ın bir uygulaması zaten var, bu yüzden oyuncu bir şey eklemiyor gibi görünüyor. Ama teşekkürler, bu iyi bir çözüm. – pipedreambomb

41

:

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

Veya daha genel:

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

Kullanımı:

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 
+5

Bu, yalnızca derleme zamanında "T" türünü zaten biliyorsanız, yararlıdır. Bu durumda, gerçekten herhangi bir koda ihtiyacınız yok. – recursive

+0

'dönüş varsayılanı (T);' – fantastory

+1

@recursive: Anonim bir yazı tipi ile çalışıyorsanız kullanışlıdır. – JJJ

3

Sen alabilirsiniz Herhangi bir koleksiyon türünden "T" tipi iki kez IEnumerable <T> uygulamak toplama türlerini, örneğin desteklemediği

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; 
} 

Not: Bu aşağıdaki ile IEnumerable <T> uygular Bunu yapıyoruz eğer Bunu desteklemek için gerekirse türlerinden bir dizi döndürür herhalde

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

... Ayrıca

, ayrıca toplama tipine göre sonucu önbelleğe isteyebilirsiniz (örneğin bir döngüde).

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

Bu aradığınız oldukça ne değildir, ama içinde yararlı olur: Bu gibi kullanabilirsiniz

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; 
} 

:

2

Benzer bir şey başarmak için bu uzatma yöntemi kullanın ilgili teknikleri göstererek.

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

'u çağırmıştım. Bu, türün bir liste-y türünün olup olmadığı sorusunu yanıtlıyor gibi görünüyor, ancak soru neyin nasıl belirlendiğiyle ilgilidir. Jenerik tip parametresi zaten bir Liste olarak bilinen bir tür ile başlatıldı. –

4

Tüm Tip değişkenine ihtiyacınız yoksa ve sadece türü kontrol etmek istiyorsanız, kolayca bir geçici değişken oluşturabilir ve operatördür. 3dGrabber en çözümünü kullanma

T checkType = default(T); 

if (checkType is MyClass) 
{} 
1

: Bir tesisin temel türünü bilmek istiyorsanız

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

//and now 

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

, şunu deneyin:

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

Sen tekrar yayınlama türü için bu birini kullanabilirsiniz genel listenin

0

Bu i

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); 
} 

Sonra yaptım = abc.GetType(). GetGenericArguments() [Bu

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

VEYA

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