Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constraint on params array of Types

Tags:

c#

In the following method:

public void Foo(params Type[] types) {}

How can I constrain the types so that each Type passed in must derive from a certain base class?

I want something along the lines of this:

public void Foo(params Type[] types) where each types : BaseClass {}

Clarification:

I want the types of the classes that derive from BaseClass, not the instances of them.

For example if Bar is a subclass of BaseClass, I want to be able to pass in typeof(Bar), not new Bar().

like image 946
S. Tarık Çetin Avatar asked Feb 04 '26 07:02

S. Tarık Çetin


1 Answers

If you want to pass an array of Type objects, than you can't do what you want. That's because constraints are part of the type system - you can set a method to get an argument of type int, or a generic method to receive a generic type parameter derived from IDisposable, or whatever, but what you have there is already a specific, concrete type - Type.

Type, confusingly, isn't part of the type system. It's just a regular class that happens to describe the type system metadata. But it's just any old class.

Being able to constrain a method to only accept a Type instance whose BaseClass property is MyBaseClass is just like being able to constrain a method to only accept string arguments whose Length == 3 - it's not a question of type (as C# sees it), but of data inside those types.

Of course, it's not unheard of in other languages to be able to create constrained types - to create a type TLA which is a type of string which must be of length 3 - but that's not how C#'s type system (currently) works.

What you can do is use generic type parameters as a wrapper:

public void Foo<T1, T2, T3>() where T1 : BaseClass, T2:BaseClass, T3:BaseClass
{
   // call untyped Foo.
   Foo(typeof(T1), typeof(T2), typeof(T3));
}

This gives you stronger type safety for some scenarios, but it won't give you the ability to pass an unbounded list of types that a params [] will.

This is conceptually similar to wrapping a method which accepts an object parameter with a typed wrapper method. If your Add(object obj) is confusing, hide it and expose Add(int i) { Add((object)i);} and Add(string s) { Add((object)s);}

like image 122
Avner Shahar-Kashtan Avatar answered Feb 05 '26 20:02

Avner Shahar-Kashtan