Search code examples
c#genericstypeof

How can I find out wether the current object is object<T> or object<T,U> in C#


I would like to know if there is a way in C# to find out if an object is object<> or object<T,U>.

In my program I deal with ConsoleCommands.
These classes inherit from the ConsoleCommandBase class.
The ConsoleCommand class is either a ConsoleCommand, ConsoleCommand<> or ConsoleCommand<T,U>.

My goal is to determine at runtime which specific ConsoleCommand I'm currently looking at. I don't want to write a lot of if-else statements to determine the current object type like I did in my code. Therefore I can add a third ConsoleCommand<T,U,V> without touching this code.

Here is my current code. It works, but I have to tell whether it is typeof(ConsoleCommand<>) or typeof(ConsoleCommand<T,U>).

for (int i = 0; i < commandList.Count; i++)
{
    if (properties[0].Equals(commandList[i].Id))
    {
        if (commandList[i] is ConsoleCommand)
        {
            (commandList[i] as ConsoleCommand).Invoke();
            validCommand = true;
            break;
        }
        else
        {
            validCommand = false;
            var command = commandList[i];
            Type[] types = command.GetMyTypes();
            if(properties.Length - 1 >= types.Length)
            {
                var typeOfCommand = typeof(ConsoleCommand<,>);
                var genericType = typeOfCommand.MakeGenericType(types);
                object[] parameters = new object[types.Length];
                for(int j=0; j<types.Length; j++)
                {
                    parameters[j] = ConvertType(properties[j + 1], types[j]);
                }
                
                genericType.GetMethod("Invoke").Invoke(command, parameters);
                validCommand = true;
            }
            break;
        }
    }
}

Solution

  • You in fact already have the code that you need, it just needs to be generisized.

    For example (and I've refactored your code a bit, both to improve and to make it work for the example)

        class Foo<X,Z> {
            public string Invoke(X x, Z z) => $"{x} {z}";
        }
        class Bar<A,B,C> {
            public string Invoke(A a, B b, C c) => $"{a} {b} {c}";
        }
    
        //then to test
    
        var foo = new Foo<string, int>();
        callCommand(foo, new string[] { "id", "a", "1" });
    
        var bar = new Bar<string, int, double>();
        callCommand(bar, new string[] { "id", "a", "2", "3.1"});
    
    
        void callCommand(object command, string[] properties){
            var typeOfCommand = command.GetType();
            var types = typeOfCommand.GetGenericArguments();
            //var genericType = typeOfCommand.MakeGenericType(types);
            object[] parameters = new object[types.Length];
            for(int j=0; j<types.Length; j++)
            {
                parameters[j] = Convert.ChangeType(properties[j + 1], types[j]);
            }
            
            var x = typeOfCommand.GetMethod("Invoke").Invoke(command, parameters);
            Console.WriteLine(x);
        }
    

    Having said this, there are better alternatives to parsing the command line especially in .net core. Such as System.CommandLine and DragonFruit