C# 有没有一种方法可以将对象强制转换回其原始类型,而不必指定每种情况?

C# 有没有一种方法可以将对象强制转换回其原始类型,而不必指定每种情况?,c#,casting,syslog,udpclient,C#,Casting,Syslog,Udpclient,我有一个不同类型对象的数组,我使用BinaryWriter将每个项目转换为其二进制等价物,以便通过网络发送结构 我现在做的是 for ( i=0;i<tmpArrayList.Count;i++) { object x=tmpArrayList[i]; if (x.GetType() == typeof(byte)) { wrt.Write((byte)x); } ........ 但除非我每次都投,否则就没用了 编辑: 在查阅了答案之后,这就

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

我现在做的是

for ( i=0;i<tmpArrayList.Count;i++)
{
   object x=tmpArrayList[i];
   if (x.GetType() ==  typeof(byte))
   {
      wrt.Write((byte)x);
   }
   ........
但除非我每次都投,否则就没用了

编辑:

在查阅了答案之后,这就是我为函数所想到的。为了测试此函数,将数组发送到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             
  }
private void TxMsg(ArrayList TxArray,IPAddress-IPAddress)
{
字节[]txbuf=新字节[0];
int sz=0;
//计算txbuf的尺寸
foreach(TxArray中的对象o)
{
if(o是字符串)
{
sz+=((字符串)(o))长度;
}
else if(o是字节[])
{
sz+=((字节[])(o))。长度;
}
else if(o是字符[])
{
sz+=((Char[])(o))。长度;
}
else//处理非数组
{
sz+=Marshal.SizeOf(o);
}
}
txbuf=新字节[sz];
System.IO.MemoryStream stm_w=新的System.IO.MemoryStream(txbuf,0,txbuf.Length);
System.IO.BinaryWriter wrt=新的System.IO.BinaryWriter(stm_w);
foreach(TxArray中的对象o)
{
bool-otypefound=false;
if(o是String)//字符串需要每个字符发送一个字节
{
otypefound=true;
字符串st=(字符串)o;

对于(int i=0;iNo)。强制转换必须在编译时已知,但实际类型仅在执行时已知

但是,请注意,有一种更好的方法可以测试调用GetType的类型。而不是:

if (x.GetType() == typeof(byte))
使用:

编辑:回答额外的问题:

“所有的类型都是什么?”好吧,我想在文档中查找BinaryWriter


“我需要担心字节和字节吗?”不,字节是系统的别名。C#中的字节。它们是相同的类型。

乔恩是对的,但我有另一个想法,你可能会发现它很有用。你是否考虑过在每个对象的传输中添加另一个字节,然后将该字节用作类型代码,告诉你将其转换到另一端的内容?

你要求的是Dyna麦克风调度,而C#3.0没有

您至少应该使用运行时检查来验证是否缺少类型


如果你有一个从类型映射到处理函数的
字典,你也许可以做一些聪明的事情。你可以在一个地方填写所有处理函数的映射。你有更好的机会做到这一点,而不是在处理发生的任何地方写一个开关。

这是一个需要一些东西的情况g打电话来

我将假设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)进行写入,但是这是为该对象完成的,而该对象无法提前知道。

您是否考虑过使用a而不是BinaryWriter

优势

  • 您可以传递对象(即任何对象),因此它可以解决您的铸造问题
  • 自动类型管理(实际上将类型头写入流)
  • 还支持复杂的引用类型
缺点

在内部使用序列化,因此:

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

    • 这里是一个使用反射的BinaryWriter解决方案

      这基本上是扫描BinaryWriter,查找只接受一个参数的方法Write,然后构建一个字典,确定哪个方法处理哪种类型,然后为每个要写入的对象找到正确的方法并在writer上调用它

      肮脏,你可能应该寻找更好的方法来完成整个工作(不仅仅是写作部分),但它应该适合你当前的需要:

      using System.IO;
      using System;
      using System.Reflection;
      using System.Collections.Generic;
      namespace ConsoleApplication14
      {
          public class Program
          {
              public static void Main()
              {
                  Dictionary<Type, MethodInfo> mapping = new Dictionary<Type, MethodInfo>();
                  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<Object> someData = new List<Object>();
                  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);
                      }
                  }
              }
          }
      }
      
      使用System.IO;
      使用制度;
      运用系统反思;
      使用System.Collections.Generic;
      命名空间控制台应用程序14
      {
      公共课程
      {
      公共静态void Main()
      {
      字典映射=新字典();
      foreach(typeof中的MethodInfo mi(BinaryWriter).GetMethods())
      {
      如果(mi.Name==“写入”)
      {
      ParameterInfo[]pi=mi.GetParameters();
      如果(pi.Length==1)
      映射[pi[0]。参数类型]=mi;
      }
      }
      List someData=新列表();
      someData.Add((字节)10);
      添加((Int32)10);
      添加((双)10);
      someData.Add((Char)10);
      添加(“测试”);
      使用(FileStream file=newfilestream(@“C:\test.dat”、FileMode.Create、FileAccess.ReadWrite))
      使用(BinaryWriter=新的BinaryWriter(文件))
      {
      foreach(someData中的对象o)
      {
      MethodInfo-mi;
      if(mapping.TryGetValue(o.GetType(),out mi))
      {
      调用(writer,新对象[]{o});
      }
      其他的
      抛出新的InvalidOperationException(“无法写入类型为“+o.GetType().FullName”的数据);
      }
      }
      }
      }
      }
      
      迫不及待地等待C#4.0。你也许应该给他看一个例子,说明如何使用dynamic关键字在C#4.0中实现它?我不知道是否可以在C#4.0中实现。事实上,我怀疑OP需要的是双动态d
      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);
          }
      }
      
      using System.IO;
      using System;
      using System.Reflection;
      using System.Collections.Generic;
      namespace ConsoleApplication14
      {
          public class Program
          {
              public static void Main()
              {
                  Dictionary<Type, MethodInfo> mapping = new Dictionary<Type, MethodInfo>();
                  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<Object> someData = new List<Object>();
                  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);
                      }
                  }
              }
          }
      }