c# casting syslog udpclient

c# - ¿Hay alguna manera de devolverle un objeto al tipo original sin especificar cada caso?



casting syslog (6)

¿Ha considerado usar un BinaryFormatter en lugar del BinaryWriter?

Ventajas

  • Puede pasar objetos s (es decir, cualquier cosa), por lo que resuelve su problema de lanzamiento.
  • Gestión automática de tipos (en realidad escribe encabezados de tipo en la secuencia).
  • Admite también tipos de referencia complejos.

Desventajas

Utiliza la serialización internamente, por lo tanto:

  • Probablemente más lento.
  • La transmisión de bytes se hace más grande (debido a los encabezados de tipo).
  • No tiene control sobre el formato de bytes, por lo tanto, no es una opción en escenarios de interoperabilidad.
  • Posibles problemas de versión (compatibilidad entre diferentes versiones de ensamblaje del tipo serializado).
  • Requiere el permiso de acceso al código de serialización (relevante en escenarios de confianza parcial).

Tengo una variedad de diferentes tipos de objetos y utilizo BinaryWriter para convertir cada elemento a su equivalente binario para que pueda enviar la estructura a través de la red.

Actualmente hago algo así como

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

El problema es que si pierdes un tipo, mi código podría romperse en el futuro.

Me gustaría hacer algo como.

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

pero no funciona a menos que haga cada lanzamiento.

Editar:

Después de consultar las respuestas, esto es lo que se me ocurrió para la función. Para probar esta función envía la matriz a 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 }


Este es un caso de necesitar algo llamado Double Dispatch .

Voy a suponer que el objeto wrt es uno que usted mismo escribió (Digamos que es del tipo Escritor). Esto es lo que puedes hacer:

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

Lo que Writer está haciendo es enviar de regreso a la entrada, diciéndole que lo use (el escritor) para escribir, sin embargo, eso se hace para ese objeto, que no se puede saber antes de tiempo.


Lo que estás pidiendo es Dynamic Dispatch , y C # 3.0 no lo tiene.

Al menos debe usar un control de tiempo de ejecución para verificar que no le falta un tipo.

Es posible que pueda hacer algo inteligente donde tenga un Dictionary que mapea desde tipos hasta funciones de procesamiento. Puede completar la asignación de todas las funciones de procesamiento en un solo lugar. Tiene más posibilidades de hacerlo bien que si escribe un interruptor donde sea que ocurra el procesamiento.


No. El molde debe conocerse en tiempo de compilación, pero el tipo real solo se conoce en el momento de la ejecución.

Sin embargo, tenga en cuenta que hay una forma mejor de probar el tipo que llama a GetType. En lugar de:

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

Utilizar:

if (x is byte)

EDITAR: Para responder las preguntas adicionales:

"¿Cuáles son todos los tipos?" Bueno, mira los documentos de BinaryWriter, supongo ...

"¿Debo preocuparme por Byte y Byte?" No, byte es un alias para System.Byte en C #. Son del mismo tipo.


Aquí hay una solución para BinaryWriter que usa reflexión.

Esto básicamente escanea BinaryWriter para métodos llamados Write que toman exactamente un parámetro, luego construye un diccionario de qué método maneja qué tipo, luego para cada objeto para escribir, encuentra el método correcto y lo llama al escritor.

Sucio, y probablemente debas buscar mejores formas de hacer todo (no solo la parte de escritura), pero debería funcionar para tus necesidades actuales:

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


Jon tiene razón, pero pensé que podría ser útil. ¿Ha considerado agregar otro byte a la transmisión de cada objeto, y luego usar ese byte como un código de tipo, diciéndole en qué lanzarlo en el otro extremo?