Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing GenericTypeDefinition of interfaces

Tags:

c#

types

generics

Simple code that I expect List<int>'s GenericTypeDefinition to contain a generic interface of ICollection<>. Yet I can't derive an acceptable type from List<int> which allows me to compare them properly.

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var a = typeof(List<int>);
        var b = typeof(ICollection<>);

        var r1 = a.GetGenericTypeDefinition().GetInterfaces();
        foreach (var x in r1)
        {
            Console.WriteLine(x);
        }
        Console.WriteLine();
        Console.WriteLine(b);
        Console.WriteLine();
        Console.WriteLine(r1.Any(x => x == b));
    }
}

Output

System.Collections.Generic.IEnumerable`1[T]
System.Collections.Generic.IReadOnlyList`1[T]
System.Collections.Generic.IReadOnlyCollection`1[T]
System.Collections.IEnumerable
System.Collections.Generic.IList`1[T]
System.Collections.Generic.ICollection`1[T]
System.Collections.ICollection
System.Collections.IList

System.Collections.Generic.ICollection`1[T]

False

I would have expected that r1 contained a type that was equal to b.

EDIT

Fixed, Jon Skeet gave me the right insight into what was happening.

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var a = typeof(List<int>);
        var b = typeof(ICollection<>);

        var r1 = a.GetInterfaces()
            .Where(x => x.IsGenericType)
            .Select(x => x.GetGenericTypeDefinition());

        foreach (var x in r1)
        {
            Console.WriteLine(x);
        }

        Console.WriteLine();
        Console.WriteLine(b);
        Console.WriteLine();
        Console.WriteLine(r1.Contains(b));


    }
}

Output

System.Collections.Generic.IEnumerable`1[T]
System.Collections.Generic.IReadOnlyList`1[T]
System.Collections.Generic.IReadOnlyCollection`1[T]
System.Collections.Generic.ICollection`1[T]
System.Collections.Generic.IList`1[T]

System.Collections.Generic.ICollection`1[T]

True
like image 426
Gareth A. Lloyd Avatar asked Mar 03 '15 09:03

Gareth A. Lloyd


1 Answers

No, the generic type definition will refer to ICollection<T> specifically, where T is the type parameter for the IList<T>.

Imagine you had something like:

public class Foo<T1, T2> : IEnumerable<T1>, IComparable<T2>

The generic type definition contains all that information - it "knows" that it's specifically IEnumerable<T1> and IComparable<T2>, not IEnumerable<T2> and IComparable<T1> for example.

You can fix the check by getting the generic type definition for each of the interfaces implemented by the type:

Console.WriteLine(r1.Any(x => x.IsGenericType && 
                              x.GetGenericTypeDefinition()  == b));
like image 109
Jon Skeet Avatar answered Oct 13 '22 13:10

Jon Skeet