强制转换为元组<对象,对象>
本文关键字:对象 元组 转换 | 更新日期: 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>
,但单独地,我可以投int
投object
,MyObj
投object
。
我该如何进行演员表?
如果要检查任何配对类型,则必须使用反射:
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,强类型可能是一个好处。
在你的代码中,你显式地检查int
和MyObj
,以及它们的位置(Item1
或Item2
),如下所示:
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答案中看到的反射,否则上面的代码可以用更少的工作完成你的意图。