考虑这段代码,我正在测试一个可能是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
投放到{{} 1}}。
如何进行演员表?
答案 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)
在您的代码中,您明确核对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的答案中所见的反射,否则上面的代码会按照您的意图执行更少的工作。