Casting to a Tuple<object,object>

眉间皱痕 提交于 2020-06-27 19:21:12

问题


Consider this chunk of code where I'm testing an unknown variable that could be an int, MyObj, or Tuple, and I'm doing some type checking to see what it is so that I can go on and handle the data differently depending on what it is:

class MyObj { }

// ...

void MyMethod(object data) {

    if (data is int) Console.Write("Datatype = int");
    else if (data is MyObj) Console.Write("Datatype = MyObj");
    else if (data is Tuple<object,object>) {

        var myTuple = data as Tuple<object,object>;
        if (myTuple.Item1 is int && myTuple.Item2 is int) Console.WriteLine("Datatype = Tuple<int,int>");
        else if (myTuple.Item1 is int && myTuple.Item2 is MyObj) Console.WriteLine("Datatype = Tuple<int,MyObj>");

        // other type checks            
    }
}

// ...

MyMethod(1);                            // Works : Datatype = int
MyMethod(new MyObj());                  // Works : Datatype = MyObj
MyMethod(Tuple.Create(1, 2));           // Fails
MyMethod(Tuple.Create(1, new MyObj());  // Fails

// and also...

var items = new List<object>() {
    1,
    new MyObj(),
    Tuple.Create(1, 2),
    Tuple.Create(1, new MyObj())
};
foreach (var o in items) MyMethod(o);

My problem is that a Tuple<int,MyObj> doesn't cast to Tuple<object,object>, yet individually, I can cast int to object and MyObj to object.

How do I do the cast?


回答1:


If you want to check for any pair type, you'll have to use reflection:

Type t = data.GetType();
if(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Tuple<,>))
{
    var types = t.GetGenericArguments();
    Console.WriteLine("Datatype = Tuple<{0}, {1}>", types[0].Name, types[1].Name)
}

You may be able to use overloading and dynamic instead of manually inspecting the type:

MyMethod(MyObject obj) { ... }
MyMethod(int i) { ... }
MyMethod(Tuple<int, int> t) { ... }
MyMethod(Tuple<int, MyObject> t) { ... }

foreach(dynamic d in items)
{
    MyMethod(d);
}

this will choose the best overload at runtime so you have access the tuple types directly.




回答2:


As you can see here, Tuple<T1, T2> is not covariant.

Rather than trying to make one method that can take any type of parameter, why not overload your function to recieve valid types you actually expect.

perhaps,

void MyMethod<T1,T2>(Tuple<T1, T2> data)
{
    // In case ToString() is overridden
    Console.WriteLine("Datatype = Tuple<{0}, {1}>",
        typeof(T1).Name,
        typeof(T2).Name);
}

void MyMethod(MyObj data)
{
    Console.WriteLine("Datatype = MyObj");
}

void MyMethod(int data)
{
    Console.WriteLine("Datatype = System.Int32");
}

This way no type checking is required, the compiler does it for you at compile time. This is not javascript, strong typing can be a benefit.




回答3:


In your code you are explicitly checking against int and MyObj, as well as against their position (Item1 or Item2) as seen here:

    if (myTuple.Item1 is int && myTuple.Item2 is int)
    else if (myTuple.Item1 is int && myTuple.Item2 is MyObj)

You can do the same explicit check using the same framework you already wrote:

    if (data is int) Console.WriteLine("Datatype = int");
    else if (data is MyObj) Console.WriteLine("Datatype = MyObj");
    else if (data is Tuple<int, int>) Console.WriteLine("Datatype = Tuple<int,int>");
    else if (data is Tuple<int, MyObj>) Console.WriteLine("Datatype = Tuple<int,MyObj>");

The downsides to the above code are the same as what you were attempting to do with Tuple<object, object>: You have to explicitly check all combinations of what could go into the tuple as well as their positions, i.e., my code will not work as written if you pass in Tuple<double, double> or Tuple<MyObj, int>, but neither would your code if it actually worked as you wanted it to. If you don't want explicit/hardcoded values then it appears you have to use reflection as seen in Lee's answer, otherwise the above code does what you were intending with less work.



来源:https://stackoverflow.com/questions/22932387/casting-to-a-tupleobject-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!