有没有办法将对象强制转换回原始类型而不指定每个案例?

我有一个不同类型对象的数组,我使用BinaryWriter将每个项目转换为二进制等效项,以便我可以通过网络发送结构。

我现在做的事情

for ( i=0;i<tmpArrayList.Count;i++) { object x=tmpArrayList[i]; if (x.GetType() == typeof(byte)) { wrt.Write((byte)x); } ........ 

问题是如果错过了一个类型,我的代码将来可能会破坏。

我想做点什么。

 object x=tmpArrayList[i]; wrt.Write(x); 

但除非我每次演员,否则它不起作用。

编辑:

在查阅答案之后,这就是我想出的function。 为了测试,该函数将数组发送到syslog。

  private void TxMsg(ArrayList TxArray,IPAddress ipaddress) { Byte[] txbuf=new Byte[0]; int sz=0; // caculate size of txbuf foreach (Object o in TxArray) { if ( o is String ) { sz+=((String)(o)).Length; } else if ( o is Byte[] ) { sz+=((Byte[])(o)).Length; } else if ( o is Char[] ) { sz+=((Char[])(o)).Length; } else // take care of non arrays { sz+=Marshal.SizeOf(o); } } txbuf = new Byte[sz]; System.IO.MemoryStream stm_w = new System.IO.MemoryStream( txbuf, 0,txbuf.Length); System.IO.BinaryWriter wrt = new System.IO.BinaryWriter( stm_w ); foreach (Object o in TxArray) { bool otypefound=false; if (o is String) // strings need to be sent one byte per char { otypefound=true; String st=(String)o; for(int i=0;i<st.Length;i++) { wrt.Write((byte)st[i]); } } else { foreach (MethodInfo mi in typeof(BinaryWriter).GetMethods()) { if (mi.Name == "Write") { ParameterInfo[] pi = mi.GetParameters(); if ((pi.Length == 1)&&(pi[0].ParameterType==o.GetType())) { otypefound=true; mi.Invoke(wrt, new Object[] { o }); } } } } if(otypefound==false) { throw new InvalidOperationException("Cannot write data of type " + o.GetType().FullName); } } IPEndPoint endpoint = new IPEndPoint(ipaddress, 514); //syslog port UdpClient udpClient_txmsg = new UdpClient(); udpClient_txmsg.Send(txbuf, txbuf.Length,endpoint); // send udp packet to syslog } 

这是使用reflection的BinaryWriter的解决方案。

这基本上会扫描BinaryWriter以获取名为Write的方法,该方法只接受一个参数,然后构建一个字典,该方法处理哪个类型,然后为每个要写入的对象找到正确的方法并在编写器上调用它。

很脏,你应该寻找更好的方法来完成整个事情(不只是写作部分),但它应该适合你当前的需求:

 using System.IO; using System; using System.Reflection; using System.Collections.Generic; namespace ConsoleApplication14 { public class Program { public static void Main() { Dictionary mapping = new Dictionary(); foreach (MethodInfo mi in typeof(BinaryWriter).GetMethods()) { if (mi.Name == "Write") { ParameterInfo[] pi = mi.GetParameters(); if (pi.Length == 1) mapping[pi[0].ParameterType] = mi; } } List someData = new List(); someData.Add((Byte)10); someData.Add((Int32)10); someData.Add((Double)10); someData.Add((Char)10); someData.Add("Test"); using (FileStream file = new FileStream(@"C:\test.dat", FileMode.Create, FileAccess.ReadWrite)) using (BinaryWriter writer = new BinaryWriter(file)) { foreach (Object o in someData) { MethodInfo mi; if (mapping.TryGetValue(o.GetType(), out mi)) { mi.Invoke(writer, new Object[] { o }); } else throw new InvalidOperationException("Cannot write data of type " + o.GetType().FullName); } } } } } 

否。演员必须在编译时知道,但实际类型只在执行时才知道。

但请注意,有一种更好的方法来测试调用GetType的类型。 代替:

 if (x.GetType() == typeof(byte)) 

使用:

 if (x is byte) 

编辑:回答额外的问题:

“这些类型是什么?” 好吧,看看BinaryWriter的文档,我猜……

“我需要担心字节和字节吗?” 不,byte是C#中System.Byte的别名。 他们是同一类型。

乔恩是对的,但我还有另一个想法,你可能觉得有用。 您是否考虑在每个对象的传输中添加另一个字节,然后将该字节用作类型代码,告诉您在另一端将其转换为什么?

您是否考虑过使用BinaryFormatter而不是BinaryWriter?

好处

  • 您可以传递对象 (即任何东西),因此它可以解决您的投射问题。
  • 自动类型管理(实际上将类型标头写入流)。
  • 也支持复杂的引用类型。

缺点

因此在内部使用序列化:

  • 可能比较慢。
  • 字节流变大(因为类型标题)。
  • 您无法控制字节格式,因此在互操作方案中不是一个选项。
  • 潜在的版本问题(序列化类型的不同程序集版本之间的兼容性)。
  • 需要序列化代码访问权限(在部分信任方案中相关)。

您要求的是动态调度 ,而C#3.0没有它。

您至少应该使用运行时检查来validation您是否错过了类型。

如果你有一个从类型映射到处理函数的Dictionary ,你可能会做一些聪明的事情。 您可以在一个地方填写所有处理function的映射。 如果在处理发生的任何地方写一个开关,你就有更好的机会做到这一点。

这是一个需要称为Double Dispatch的事情。

我将假设wrt对象是你自己编写的(让我们说它是Writer类型)。 这是你可以做的:

 class Writer { void write(byte b) { // write bytes here } void write(Writable something) { something.writeOn(this); } } interface Writeable { void writeOn(Writer writer); } class SomeObject implements Writeable { private Object someData; private Object moreData; void writeOn(Writer writer) { writer.write(convertToByte(someData)); writer.write(convertToByte(moreData)); } } class AnotherObject implements Writeable { private int x; private int y; private int z; void writeOn(Writer writer) { writer.write((byte)x); writer.write((byte)y); writer.write((byte)z); } } 

Writer正在做的是调度回输入,告诉它使用它(Writer)来编写,但这是为该对象完成的,这是无法提前知道的。