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 ConsoleCommand
s.
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;
}
}
}
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