强制转换为元组<对象,对象>

本文关键字:对象 元组 转换 | 更新日期: 2023-09-27 17:57:12

考虑这个代码块,我正在测试一个未知变量,该变量可能是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>,但单独地,我可以投intobjectMyObjobject

我该如何进行演员表?

强制转换为元组<对象,对象>

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

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

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

正如你在这里看到的,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,强类型可能是一个好处。

在你的代码中,你显式地检查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答案中看到的反射,否则上面的代码可以用更少的工作完成你的意图。