Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# check object type against multiple types

IS there a way to pass an array of types to the "is" operator?

I am trying to simplify the syntax of checking an object against multiple types.

Something like:

public static function bool IsOfType(object Obj,params Type[] Types)

This would however require the following usage:

if(X.IsOfType(typeof(int),typeof(float))
{...}

I would like to do something like:

if(X is {int,float})

or

if(X.IsOfType(int,float))

or even

public static bool ISOfType<T[]>(this object Obj){...}
if(X.ISOfType<int,float>())

I think they are all impossible.

like image 952
Jeff Holodnak Avatar asked Apr 13 '16 16:04

Jeff Holodnak


3 Answers

If you're okay with passing the types as generic arguments, there is a solution. Unfortunately, C# doesn't support variadic generics. You have to define the function for each generic arity.

public static bool IsOfType<T>(this object obj) => obj is T;
public static bool IsOfType<T1, T2>(this object obj) => obj is T1 || obj is T2;
public static bool IsOfType<T1, T2, T3>(this object obj) => obj is T1 || obj is T2 || obj is T3;
public static bool IsOfType<T1, T2, T3, T4>(this object obj) => obj is T1 || obj is T2 || obj is T3 || obj is T4;
public static bool IsOfType<T1, T2, T3, T4, T5>(this object obj) => obj is T1 || obj is T2 || obj is T3 || obj is T4 || obj is T5;
public static bool IsOfType<T1, T2, T3, T4, T5, T6>(this object obj) => obj is T1 || obj is T2 || obj is T3 || obj is T4 || obj is T5 || obj is T6;
public static bool IsOfType<T1, T2, T3, T4, T5, T6, T7>(this object obj) => obj is T1 || obj is T2 || obj is T3 || obj is T4 || obj is T5 || obj is T6 || obj is T7;
public static bool IsOfType<T1, T2, T3, T4, T5, T6, T7, T8>(this object obj) => obj is T1 || obj is T2 || obj is T3 || obj is T4 || obj is T5 || obj is T6 || obj is T7 || obj is T8;

I doubt you'll need more than 8 types but if you do, just define more overloads.

like image 84
Theodoros Chatzigiannakis Avatar answered Nov 14 '22 21:11

Theodoros Chatzigiannakis


With C# 10, you can use pattern matching to test an object for multiple types.

Example:

public bool TestObject<T>(T obj)
{
    if (obj is not null and (int or float or uint))
    {
        // obj is not null and guaranteed to be an int, float or uint 
    }
}

Example 2 (in case you want to use the value):

public bool TestIntOrFloat<T>(T obj)
{
    if (obj is not (int or float))
    {
        // obj is neither int or float
    }
    else if (obj is int i)
    {
        // obj is an integer and can be used with the variable 'i'
    }
    else if (obj is float f)
    {
        // obj is a floating number and can be used with the variable 'f'
    }
}
like image 3
Stacklysm Avatar answered Nov 14 '22 21:11

Stacklysm


It can looks crazy, but you can use the following Fluent syntax:

object someInstance = 5.0;
if(someInstance
    .Is<int>()
    .Or<double>()) {
    // ...
}

Here the fluent-syntax is implemented as follows:

static class FluentIs {
    public static IsResult Is<T>(this object target) {
        return new IsResult(target, () => target is T);
    }
    public static IsResult Or<T>(this IsResult prev) {
        return new IsResult(prev, (v, x) => v || (x is T));
    }
    public class IsResult {
        Func<bool> value;
        object target;
        internal IsResult(IsResult r, Func<bool, object, bool> getValue) :
            this(r.target, () => getValue(r.value(), r.target)) {
        }
        internal IsResult(object target, Func<bool> value) {
            this.target = target;
            this.value = value;
        }
        // bool Operators
        public static bool operator true(IsResult r) { return r.value(); }
        public static bool operator false(IsResult r) { return !r.value(); }
    }
}
like image 2
DmitryG Avatar answered Nov 14 '22 21:11

DmitryG