转换为元组<object,object> </object,object>

时间:2014-04-08 09:04:53

标签: c# generics casting tuples

考虑这段代码,我正在测试一个可能是int,MyObj或Tuple的未知变量,我正在做一些类型检查以查看它是什么,以便我可以继续处理数据取决于它是什么:

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

我的问题是Tuple<int,MyObj>不会投放到Tuple<object,object>,但我可以单独将int投放到objectMyObj投放到{{} 1}}。

如何进行演员表?

3 个答案:

答案 0 :(得分:2)

如果要检查任何配对类型,则必须使用反射:

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

您可以使用重载和动态而不是手动检查类型:

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

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

这将在运行时选择最佳重载,因此您可以直接访问元组类型。

答案 1 :(得分:2)

正如您所看到的,here, Tuple<T1, T2>不是协变的。

为什么不重载你的函数以接收你实际期望的有效类型,而不是试图创建一个可以接受任何类型参数的方法。

也许

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

这样就不需要进行类型检查,编译器会在编译时为你完成。这不是javascript,强打字可能是一种好处。

答案 2 :(得分:0)

在您的代码中,您明确核对intMyObj,以及其位置(Item1Item2),如下所示:

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

您可以使用您已编写的相同框架执行相同的显式检查:

    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>");

上述代码的缺点与您尝试使用Tuple<object, object>的内容相同:您必须明确检查可以进入元组的所有组合以及它们的位置,即我的代码如果您传入Tuple<double, double>Tuple<MyObj, int>,则无法按照书面形式运行,但如果您的代码实际上按照您的意愿运行,则代码也不会。如果您不想要显式/硬编码值,那么看起来您必须使用Lee的答案中所见的反射,否则上面的代码会按照您的意图执行更少的工作。