SoFunction
Updated on 2025-03-07

.NET/C# Detailed explanation of how to determine whether a class is a generic type or a subtype of a generic interface

Preface

Generics: Use parameterized types to implement multiple data types on the same code. Use "parametric types" to abstract types to achieve flexible reuse. Generics can be seen everywhere in the .NET class library, especially in arrays and collections. The existence of generics has greatly improved the development efficiency of programmers. More importantly, C# generics are safer than C++ template use, and achieve performance improvement by avoiding packing and unboxing operations. Therefore, it is necessary for us to master and make good use of this powerful language feature.

C# generic features:

1. If the parameters of the instantiated generic type are the same, the JIT editor will reuse the type, so the dynamic generic ability of C# avoids the problem of code bloating that may be caused by C++ static templates.

2. C# generic types carry rich metadata, so C# generic types can be applied to powerful reflection technology.

3. C# generics adopt the constraint method of "base class, interface, constructor, value type/reference type" to achieve "display constraints" on type parameters. While improving type safety, it also loses the high flexibility of the implicit constraints based on "signature" of C++ templates.

.NET provides many methods to determine that a certain type or instance is a subclass of a certain class or an interface implementation class. However, once this matter involves generics, it is not so worry-free.

This article will provide methods to judge a generic interface implementation or a generic type subclass.

There is no method in .NET

For instances, these methods are provided in .NET to determine:

if (instance is Foo || instance is IFoo)
{
}

For types, these methods are provided in .NET to determine:

if (typeof(Foo).IsAssignableFrom(type) || typeof(IFoo).IsAssignableFrom(type))
{
}

Or, if you don't need to judge the interface, just the type:

if ((typeof(Foo)))
{
}

For typeof keywords, more than just writetypeof(Foo) , can also writetypeof(Foo<>) . This can get the generic version Foo<T> type.

However, if you try to get this generic versiontypeof(Foo<>)Perform all the above judgments and you will find that all if conditions will be false.

We need to write our own methods

typeof(Foo<>)andtypeof(Foo<SomeClass>) The relationship between them is the relationship brought by the GetGenericTypeDefinition function.

So we can make full use of this to complete the judgment of generic types.

For example, we need to judge the interface:

public static bool HasImplementedRawGeneric(this Type type, Type generic)
{
 // traverse all interfaces implemented by the type to determine whether there is an interface that is a generic and is an instance of the original generic specified in the parameter. return ().Any(x =&gt; generic == ( ? () : x));
}

And if you need to judge the type, you need to traverse the base class of this class:

public static bool IsSubClassOfRawGeneric([NotNull] this Type type, [NotNull] Type generic)
{
 if (type == null) throw new ArgumentNullException(nameof(type));
 if (generic == null) throw new ArgumentNullException(nameof(generic));

 while (type != null && type != typeof(object))
 {
 isTheRawGenericType = IsTheRawGenericType(type);
 if (isTheRawGenericType) return true;
 type = ;
 }

 return false;

 bool IsTheRawGenericType(Type test)
 => generic == ( ? () : test);
}

So, we can synthesize these two methods into one to achieve an effect similar to IsAssignableFrom, but this time it will support the original interface (that is,typeof(Foo<>) )。

/// &lt;summary&gt;
/// Determine whether the specified type <paramref name="type"/> is a subtype of the specified generic type, or the specified generic interface is implemented./// &lt;/summary&gt;
/// <param name="type">Types that need to be tested.  </param>/// <param name="generic">generic interface type, pass in typeof(IXxx<>)</param>/// <returns> Returns true if it is a subtype of a generic interface, otherwise returns false.  </returns>public static bool HasImplementedRawGeneric([NotNull] this Type type, [NotNull] Type generic)
{
 if (type == null) throw new ArgumentNullException(nameof(type));
 if (generic == null) throw new ArgumentNullException(nameof(generic));

 // Test interface. var isTheRawGenericType = ().Any(IsTheRawGenericType);
 if (isTheRawGenericType) return true;

 // Test type. while (type != null &amp;&amp; type != typeof(object))
 {
 isTheRawGenericType = IsTheRawGenericType(type);
 if (isTheRawGenericType) return true;
 type = ;
 }

 // No matching interface or type was found. return false;

 // Test whether a type is the specified original interface. bool IsTheRawGenericType(Type test)
 =&gt; generic == ( ? () : test);
}

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.