I have an array of different type objects and I use a BinaryWriter to convert each item to its binary equivalent so I can send the structure over the network.
I currently do something like
for ( i=0;i<tmpArrayList.Count;i++)
{
object x=tmpArrayList[i];
if (x.GetType() == typeof(byte))
{
wrt.Write((byte)x);
}
........
The problem is that if miss a type them my code might break in the future.
I would like to do something like.
object x=tmpArrayList[i];
wrt.Write(x);
but it doesn't work unless I do each cast.
Edit:
After consulting the answers this is what I came up with for the function. For testing this function sends the array to 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
}
Jon's right, but I had another thought that you may find useful. Have you considered adding in another byte to the transmission of each object, then using that byte as a type code, telling you what to cast it to on the other end?
What you're asking for is Dynamic Dispatch, and C# 3.0 doesn't have it.
You should at least use a runtime check to verify that you aren't missing a type.
You may be able to do something clever where you have a
Dictionary
that maps from types to processing functions. You can fill in the mapping for all processing functions in one place. You have a better chance of getting this right than if you write a switch wherever the processing happens.No. The cast has to be known at compile-time, but the actual type is only known at execution time.
Note, however, that there's a better way of testing the type calling GetType. Instead of:
Use:
EDIT: To answer the extra questions:
"What are all the types?" Well, look down the docs for BinaryWriter, I guess...
"Do I need to worry about byte and Byte?" No, byte is an alias for System.Byte in C#. They're the same type.
Have you considered using a BinaryFormatter instead of the BinaryWriter?
Advantages
Disadvantages
Uses Serialization internally, therefore:
This is a case of needing something called Double Dispatch.
I'm going to assume that the wrt object is one you wrote yourself (Let's say it is of type Writer). Here is what you could do:
What Writer is doing is dispatching back to the input, telling it to use it (the Writer) to write, however that is done for that object, which cannot be known ahead of time.
Here is a solution for BinaryWriter that uses reflection.
This basically scans BinaryWriter for methods named Write that takes exactly one parameter, then builds a dictionary of which method handles which type, then for each object to write, finds the right method and calls it on the writer.
Dirty, and you should probably look for better ways of doing the whole thing (not just the writing part), but it should work for your current needs: