C# Generic List <T> How to Get the Type of T

C# generic list T how to get the type of T?

Type type = pi.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition()
== typeof(List<>))
{
Type itemType = type.GetGenericArguments()[0]; // use this...
}

More generally, to support any IList<T>, you need to check the interfaces:

foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition()
== typeof(IList<>))
{
Type itemType = type.GetGenericArguments()[0];
// do something...
break;
}
}

Get actual type of T in a generic List T

It depends on what exactly you’re asking:

  • While writing code inside a generic type Blah<T>, how do I get the reflection type T?

    Answer: typeof(T)

  • I have an object which contains a List<T> for some type T. How do I retrieve the type T via reflection?

    Short answer: myList.GetType().GetGenericArguments()[0]

    Long answer:

    var objectType = myList.GetType();
    if (!objectType.IsGenericType() ||
    objectType.GetGenericTypeDefinition() != typeof(List<>))
    {
    throw new InvalidOperationException(
    "Object is not of type List<T> for any T");
    }
    var elementType = objectType.GetGenericArguments()[0];

How to get the type of T from a member of a generic class or method

If I understand correctly, your list has the same type parameter as the container class itself. If this is the case, then:

Type typeParameterType = typeof(T);

If you are in the lucky situation of having object as a type parameter, see Marc's answer.

Get List T by its generic type T from a collection (C#)

Simply store the lists as an object in the internal dictionary, and cast to the specified type when required. No sense trying to store the lists as a list-of-modelbase since the lists are not of that type.

Something like this:

public class Container {    
private readonly ConcurrentDictionary<Type, object> _container =
new ConcurrentDictionary<Type, object>();

public List<TModel> Get<TModel>() where TModel: ModelBase {
return _container.GetOrAdd(typeof(TModel), t => new List<TModel>()) as List<TModel>;
}
}

I'm using a concurrent dictionary to make sure only a single list instance is created for each type. You can easily add a method to store an existing list in the dictionary if you want.

// Usage
var container = new Container();
var person = container.Get<Person>();
var orders = container.Get<Order>();

Get the Type of T of the generic List T object

Simple:

Type type = list.GetType().GetGenericArguments()[0];
// The first argument will be the `T` inside `List<T>`... so the list type ;)

Casting of generic type T to List for list equality checking

Would something like this work for you?

public static bool Compare(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;

if (x is null || y is null)
return false;

if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());

return x.Equals(y);
}

Usage:

var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 1, 2, 3 };
var c = new List<int> { 1, 2, 4 };
var d = new List<bool>{ true, false, true };
var e = "string";
var f = new Collection<int> { 1, 2, 3 };
var g = new List<short> { 1, 2, 3 };

Console.WriteLine(Compare(a, b)); // True
Console.WriteLine(Compare(a, c)); // False
Console.WriteLine(Compare(a, d)); // False
Console.WriteLine(Compare(a, e)); // False
Console.WriteLine(Compare(a, f)); // True - might not be what you want,
Console.WriteLine(Compare(a, g)); // False

Console.ReadLine();

Note that because I'm using SequenceEqual() (as per your suggestion) then the List<int> compares true to the equivalent Collection<int>. I think this is probably what you want, since a List<int> is a Collection<int>, but just so you are aware.

Also note that you shouldn't call the method Compare() in your code - it might cause people to confuse it with IComparer.Compare().

Do be aware that this solution is likely to be significantly slower than just doing:

public static bool CompareDynamic<T>(T x, T y)
{
return typeof(T).IsSubClassOfGenericBaseType(typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}

This is due to all the casting (and hence boxing, if the elements are value types). If there are few elements, then it won't matter much but for large collections that could be a problem.


For completeness, here is some benchmark code that compares the performance of casting versus using dynamic for a fairly large int list:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

namespace Demo
{
[SimpleJob(RuntimeMoniker.Net50)]
public class Program
{
List<int> a = Enumerable.Range(1, 100_000).ToList();
List<int> b = Enumerable.Range(1, 100_000).ToList();

static void Main()
{
BenchmarkRunner.Run<Program>();
Console.ReadLine();
}

[Benchmark]
public void ViaCompareCast()
{
CompareCast(a, b);
}

[Benchmark]
public void ViaCompareDynamic()
{
CompareDynamic(a, b);
}

public static bool CompareCast(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;

if (x is null || y is null)
return false;

if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());

return x.Equals(y);
}

public static bool CompareDynamic<T>(T x, T y)
{
return IsSubClassOfGenericBaseType(typeof(T), typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}

static bool IsSubClassOfGenericBaseType(Type type, Type genericBaseType)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == genericBaseType)
return true;

if (type.BaseType != null)
return IsSubClassOfGenericBaseType(type.BaseType, genericBaseType);

return false;
}
}
}

The results (for a .net 5.0 release build) are as follows:

|            Method |       Mean |    Error |    StdDev |     Median |
|------------------ |-----------:|---------:|----------:|-----------:|
| ViaCompareCast | 4,930.6 us | 96.79 us | 191.04 us | 4,832.1 us |
| ViaCompareDynamic | 667.6 us | 12.67 us | 28.07 us | 652.7 us |

As you can see, the version using dynamic is more than 70 times faster for this particular data set. So you pays your money and you makes your choice!

How to get type of T generic?

You can use typeof to get the type of a generic parameter: typeof(T)

Pass table type as T for generic list

What you are trying to do won't compile (as I am sure you know)

public static void ListFromType(Type suppliedTableType)
{
List<supliedTableType> myList = new List<suppliedTableType>();
}

First off the method is void which means it returns nothing, secondly you are using a System.Type instance as a generic type parameter which does not work.

When you look at the problem it begs the question, why even do this at all? You always have to know the type to create an instance of the list, so why not just allocate a List directly all the time? Why call an ancillary method to simply do:

List<myTable> someList = new List<myTable>();
// or to save yourself from typing myTable twice
var someList = new List<myTable>();

If you really want some fancy Linq that achieves the same exact thing you can use Enumerable.Empty<T> and call ToList() on it:

List<myTable> someList = Enumerable.Empty<myTable>().ToList();

If your goal is to create Lists based on a System.Type variable (as indicated in your non-compiling code sample), you would have to use a mixture of Reflection and other methods of Enumerable. @Camilo has pointed out a fairly relevant question and answer that could help along those lines. Your question was tagged with Generics and not Reflection so I don't want to make too many assumptions.



Related Topics



Leave a reply



Submit