HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Check if a type is of any from a list of types?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fromanytypetypeslistcheck

Problem

I need to check whether a generic type parameter is in a set of valid types and have created extension methods to do a run time check:

public static bool Is(this Type type, params Type[] types) {
  return types.Any(t => t == type);
}

public static bool Is(this Type type) {
  return type.Is(typeof (T1));
}

public static bool Is(this Type type) {
  return type.Is(typeof (T1), typeof (T2));
}


With additional methods for T3 - T#...

Usage (in constructor for the generic class):

if(!typeof(T).Is())
    throw new ArgumentException("T must be a type.");


But I would prefer a compile time check (which I don't believe is possible). Failing that, any suggestions on improvements are appreciated.

Solution

Here is a run-time and a compile-time approach. For the compile-time approach I only show how it works for 3 type parameters and for 20 type parameters to show the concept. You can easily add more methods/classes for the number of type parameters you need.

Scroll down to the bottom to see some usage examples.

public static class RuntimeTypeCheckExtensions
{
    public static bool IsAssignableToAnyOf(this Type typeOperand, IEnumerable types)
    {
        return types.Any(type => type.IsAssignableFrom(typeOperand));
    }

    public static bool IsAssignableToAnyOf(this Type typeOperand, params Type[] types)
    {
        return IsAssignableToAnyOf(typeOperand, types.AsEnumerable());
    }

    public static bool IsAssignableToAnyOf(this Type typeOperand)
    {
        return typeOperand.IsAssignableToAnyOf(typeof(T1), typeof(T2), typeof(T3));
    }

    public static bool IsAssignableToAnyOf(this Type typeOperand)
    {
        return typeOperand.IsAssignableToAnyOf(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20));
    }
}

public static class CompileTimeTypeCheckUtils
{
    public static IsAssignableToAnyOfWrapper IsAssignableToAnyOf()
    {
        return new IsAssignableToAnyOfWrapper();
    }

    public static IsAssignableToAnyOfWrapper IsAssignableToAnyOf()
    {
        return new IsAssignableToAnyOfWrapper();
    }
}

public class IsAssignableToAnyOfWrapper
{
    public void OperandToCheck(T1 operand) { }
    public void OperandToCheck(T2 operand) { }
    public void OperandToCheck(T3 operand) { }
}

public class IsAssignableToAnyOfWrapper
{

    public void OperandToCheck(T1 operand) { }
    public void OperandToCheck(T2 operand) { }
    public void OperandToCheck(T3 operand) { }
    public void OperandToCheck(T4 operand) { }
    public void OperandToCheck(T5 operand) { }
    public void OperandToCheck(T6 operand) { }
    public void OperandToCheck(T7 operand) { }
    public void OperandToCheck(T8 operand) { }
    public void OperandToCheck(T9 operand) { }
    public void OperandToCheck(T10 operand) { }
    public void OperandToCheck(T11 operand) { }
    public void OperandToCheck(T12 operand) { }
    public void OperandToCheck(T13 operand) { }
    public void OperandToCheck(T14 operand) { }
    public void OperandToCheck(T15 operand) { }
    public void OperandToCheck(T16 operand) { }
    public void OperandToCheck(T17 operand) { }
    public void OperandToCheck(T18 operand) { }
    public void OperandToCheck(T19 operand) { }
    public void OperandToCheck(T20 operand) { }
}


Usages:

Type someType = ...

// Three example usages of run-time check (using generic types, params and IEnumerable):
if (someType.IsAssignableToAnyOf())
{
}

if (someType.IsAssignableToAnyOf(typeof(string), typeof(int), typeof(double)))
{
}

IEnumerable enumerableOfAcceptedTypes = new Type[]
{
    typeof (string),
    typeof (int),
    typeof (double)
};

if (someType.IsAssignableToAnyOf(enumerableOfAcceptedTypes))
{
}

// Two example usages of compile-time check:
CompileTimeTypeCheckUtils.IsAssignableToAnyOf().OperandToCheck(5); // ().OperandToCheck(5F); // <-- Compile-time error

Code Snippets

public static class RuntimeTypeCheckExtensions
{
    public static bool IsAssignableToAnyOf(this Type typeOperand, IEnumerable<Type> types)
    {
        return types.Any(type => type.IsAssignableFrom(typeOperand));
    }

    public static bool IsAssignableToAnyOf(this Type typeOperand, params Type[] types)
    {
        return IsAssignableToAnyOf(typeOperand, types.AsEnumerable());
    }

    public static bool IsAssignableToAnyOf<T1, T2, T3>(this Type typeOperand)
    {
        return typeOperand.IsAssignableToAnyOf(typeof(T1), typeof(T2), typeof(T3));
    }

    public static bool IsAssignableToAnyOf<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>(this Type typeOperand)
    {
        return typeOperand.IsAssignableToAnyOf(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10), typeof(T11), typeof(T12), typeof(T13), typeof(T14), typeof(T15), typeof(T16), typeof(T17), typeof(T18), typeof(T19), typeof(T20));
    }
}

public static class CompileTimeTypeCheckUtils
{
    public static IsAssignableToAnyOfWrapper<T1, T2, T3> IsAssignableToAnyOf<T1, T2, T3>()
    {
        return new IsAssignableToAnyOfWrapper<T1, T2, T3>();
    }

    public static IsAssignableToAnyOfWrapper<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> IsAssignableToAnyOf<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>()
    {
        return new IsAssignableToAnyOfWrapper<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>();
    }
}

public class IsAssignableToAnyOfWrapper<T1, T2, T3>
{
    public void OperandToCheck(T1 operand) { }
    public void OperandToCheck(T2 operand) { }
    public void OperandToCheck(T3 operand) { }
}

public class IsAssignableToAnyOfWrapper<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>
{

    public void OperandToCheck(T1 operand) { }
    public void OperandToCheck(T2 operand) { }
    public void OperandToCheck(T3 operand) { }
    public void OperandToCheck(T4 operand) { }
    public void OperandToCheck(T5 operand) { }
    public void OperandToCheck(T6 operand) { }
    public void OperandToCheck(T7 operand) { }
    public void OperandToCheck(T8 operand) { }
    public void OperandToCheck(T9 operand) { }
    public void OperandToCheck(T10 operand) { }
    public void OperandToCheck(T11 operand) { }
    public void OperandToCheck(T12 operand) { }
    public void OperandToCheck(T13 operand) { }
    public void OperandToCheck(T14 operand) { }
    public void OperandToCheck(T15 operand) { }
    public void OperandToCheck(T16 operand) { }
    public void OperandToCheck(T17 operand) { }
    public void OperandToCheck(T18 operand) { }
    public void OperandToCheck(T19 operand) { }
    public void OperandToCheck(T20 operand) { }
}
Type someType = ...

// Three example usages of run-time check (using generic types, params and IEnumerable):
if (someType.IsAssignableToAnyOf<string, int, double>())
{
}

if (someType.IsAssignableToAnyOf(typeof(string), typeof(int), typeof(double)))
{
}

IEnumerable<Type> enumerableOfAcceptedTypes = new Type[]
{
    typeof (string),
    typeof (int),
    typeof (double)
};

if (someType.IsAssignableToAnyOf(enumerableOfAcceptedTypes))
{
}

// Two example usages of compile-time check:
CompileTimeTypeCheckUtils.IsAssignableToAnyOf<string, int, long>().OperandToCheck(5); // <-- No compile-time error

CompileTimeTypeCheckUtils.IsAssignableToAnyOf<string, int, long>().OperandToCheck(5F); // <-- Compile-time error

Context

StackExchange Code Review Q#34041, answer score: 3

Revisions (0)

No revisions yet.