简体   繁体   中英

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.

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'
    }
}

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.

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(); }
    }
}

My "chosen" solution was to use my handy "In" extension function to validate based on object type name.

    public static bool IsAnyOf(this object Obj,params string[] TypeNames)
    {
        return Obj.GetType().Name.In(TypeNames);
    }
    public static bool In(this string Needle,params string [] Haystack)
    {
        foreach (string straw in Haystack)
            if (straw == Needle)
                return true;
        return false;
    }

Usage:

    public static void CheckAll(this TreeNode Node)
    {
        foreach(TreeNode Child in Node.Nodes)
        {
            if(Child.GetType().Name.In("ChildTablesNode","ChildTableNode"))
            {
                Child.Checked = Node.Checked;
                Child.CheckAll();
            }
        }
    }

    private void ctxTree_Opening(object sender, CancelEventArgs e)
    {
        TreeNode nSelected = Tree.SelectedNode;

        ctxScript.Visible = !nSelected.IsAnyOf("TablesNode"
            , "ViewsNode"
            , "ProceduresNode"
            , "UserTableTypesNode"
            , "FunctionsNode"
            , "ServerNode"
            , "DatabaseNode"
            , "ColumnsNode"
            , "ColumnNode"
            , "TriggersNode");

        Type[] x = { typeof(int) };

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM