469,890 Members | 1,607 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,890 developers. It's quick & easy.

Problem casting a byte[] to a class

I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?
Oct 23 '06 #1
12 3062
Your assuming the data is sequentially stored and no other data exist in the
class, both assumptions are incorrect.

Normally you can serialize your class and desterilized but if the data needs
to be in a compact byte array which I have found need for several times you
will need to parse the data manually. I think you can overload the
serialization function but I have found the below simpler.

class TestA {
public ushort val1;
public ushort val2;
public ushort val3;

public TestA(byte[] data)
{
val1 = BitConverter.ToUInt16(0);
val2 = BitConverter.ToUInt16(2);
val3 = BitConverter.ToUInt16(4);
}
public ToArray
{
get {
MemoryStream ms = new MemoryStream();
ms.Wirte(BitConverter.GetBytes(val1, 0, 2);
ms.Wirte(BitConverter.GetBytes(val2, 0, 2);
ms.Wirte(BitConverter.GetBytes(val3, 0, 2);
ms.Capacity = ms.Length;
return ms.ToArray();
}
}
}

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?

Oct 23 '06 #2
O.B. <fu******@bellsouth.netwrote:
I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.
You can't do that in C# (thank goodness, IMO). You should either look
at serialization, or add a method to TestA to convert an array of bytes
(or a stream) into an instance of TestA.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Oct 23 '06 #3
Oh by the way if you convert to a structure and set the offsets manually you
can then do a memory copy to accomplish what you did in C.

Sort of like this, don't do it as often so a little fuzzer on how.

[StructLayout(LayoutKind.Explicit)]
public struct TestA
{
[FieldOffset(0)] public ushort Val1;
[FieldOffset(2)] public ushort Val2;
[FieldOffset(4)] public ushort Val2;
}

Marshal.Copy(Data, 0, IntPtr <TestA>, 6);

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?

Oct 23 '06 #4
John J. Hughes II <no@invalid.comwrote:
Your assuming the data is sequentially stored and no other data exist in the
class, both assumptions are incorrect.

Normally you can serialize your class and desterilized but if the data needs
to be in a compact byte array which I have found need for several times you
will need to parse the data manually. I think you can overload the
serialization function but I have found the below simpler.
Note that for your solution, the line

ms.Capacity = ms.Length;

is unnecessary.

Personally, I'd prefer to create the 6 byte array to start with, and
then populate it. The "standard" BitConverter doesn't have any way to
convert into the middle of an existing array, but my own one does :)

See http://www.pobox.com/~skeet/csharp/miscutil and the
EndianBitConverter class.

In this case, the code might be (converting it to a method rather than
a property);

public byte[] ToArray()
{
EndianBitConverter converter = EndianBitConverter.Little;
byte[] ret = new byte[6];
converter.CopyBytes (val1, ret, 0);
converter.CopyBytes (val2, ret, 2);
converter.CopyBytes (val3, ret, 4);
return ret;
}

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Oct 23 '06 #5
Actually, the code is bit more complex than what I posted. I'm reading
data off of socket. In C++, I used a static_cast to cast the data to a
union. In C#, I have used StructLayout and FieldOffset to acquire the
"union" behavior. I just need the ability to overlay a structure
(perhaps better than a class for this use case) on top of that byte array.

The problem that I have with "as" when I use a struct is the following
error:
The as operator must be used with a reference type ('TEST.TestA' is a
value type)

Also, I really can't do an assignment on a per attribute basis. The
data received over the socket is in big endian. I prefer to store it in
big-endian and not waste any CPU cycles to convert it to little endian
(speed is key in this application). The implicit and explicit operators
are overridden to query header information from the data received. The
data is then forwarded over many other socket connections in big-endian
format; thus no byte-swapping conversions are required for the majority
of the received data.

Is there no way in C# to map a struct directly on top of a block of memory?

John J. Hughes II wrote:
Your assuming the data is sequentially stored and no other data exist in the
class, both assumptions are incorrect.

Normally you can serialize your class and desterilized but if the data needs
to be in a compact byte array which I have found need for several times you
will need to parse the data manually. I think you can overload the
serialization function but I have found the below simpler.

class TestA {
public ushort val1;
public ushort val2;
public ushort val3;

public TestA(byte[] data)
{
val1 = BitConverter.ToUInt16(0);
val2 = BitConverter.ToUInt16(2);
val3 = BitConverter.ToUInt16(4);
}
public ToArray
{
get {
MemoryStream ms = new MemoryStream();
ms.Wirte(BitConverter.GetBytes(val1, 0, 2);
ms.Wirte(BitConverter.GetBytes(val2, 0, 2);
ms.Wirte(BitConverter.GetBytes(val3, 0, 2);
ms.Capacity = ms.Length;
return ms.ToArray();
}
}
}

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?

Oct 23 '06 #6
This is *real* close to what I want. The only drawback is that I'm
having to instantiate new memory for the TestA structure before calling
Marshal. The UdpClient is already returning an allocated byte array.
This application has to run as close to real-time as possible.

TestA test;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
Marshal.Copy(testArray, 0, (IntPtr)(&test), 6);

John J. Hughes II wrote:
Oh by the way if you convert to a structure and set the offsets manually you
can then do a memory copy to accomplish what you did in C.

Sort of like this, don't do it as often so a little fuzzer on how.

[StructLayout(LayoutKind.Explicit)]
public struct TestA
{
[FieldOffset(0)] public ushort Val1;
[FieldOffset(2)] public ushort Val2;
[FieldOffset(4)] public ushort Val2;
}

Marshal.Copy(Data, 0, IntPtr <TestA>, 6);

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?

Oct 23 '06 #7
See my other post with [StructLayout(LayoutKind.Explicit)] and Marshal.Copy.

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
Actually, the code is bit more complex than what I posted. I'm reading
data off of socket. In C++, I used a static_cast to cast the data to a
union. In C#, I have used StructLayout and FieldOffset to acquire the
"union" behavior. I just need the ability to overlay a structure (perhaps
better than a class for this use case) on top of that byte array.

The problem that I have with "as" when I use a struct is the following
error:
The as operator must be used with a reference type ('TEST.TestA' is a
value type)

Also, I really can't do an assignment on a per attribute basis. The data
received over the socket is in big endian. I prefer to store it in
big-endian and not waste any CPU cycles to convert it to little endian
(speed is key in this application). The implicit and explicit operators
are overridden to query header information from the data received. The
data is then forwarded over many other socket connections in big-endian
format; thus no byte-swapping conversions are required for the majority of
the received data.

Is there no way in C# to map a struct directly on top of a block of
memory?

John J. Hughes II wrote:
>Your assuming the data is sequentially stored and no other data exist in
the class, both assumptions are incorrect.

Normally you can serialize your class and desterilized but if the data
needs to be in a compact byte array which I have found need for several
times you will need to parse the data manually. I think you can overload
the serialization function but I have found the below simpler.

class TestA {
public ushort val1;
public ushort val2;
public ushort val3;

public TestA(byte[] data)
{
val1 = BitConverter.ToUInt16(0);
val2 = BitConverter.ToUInt16(2);
val3 = BitConverter.ToUInt16(4);
}
public ToArray
{
get {
MemoryStream ms = new MemoryStream();
ms.Wirte(BitConverter.GetBytes(val1, 0, 2);
ms.Wirte(BitConverter.GetBytes(val2, 0, 2);
ms.Wirte(BitConverter.GetBytes(val3, 0, 2);
ms.Capacity = ms.Length;
return ms.ToArray();
}
}
}

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
>>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?
Oct 23 '06 #8
Jon,

Most of my solutions (problems) have the wrong Endean so I also have a class
for converting. Maybe someday when I have time I will look at yours, you
might have some better ways of handling problems.

Yes you are correct about the ToArray, when I first write the function I was
using the GetBuffer function which was returning the entire capacity. I
later switch to the ToArray function and never removed it, thanks for the
pointer.

Regards,
John

"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP************************@msnews.microsoft.c om...
John J. Hughes II <no@invalid.comwrote:
>Your assuming the data is sequentially stored and no other data exist in
the
class, both assumptions are incorrect.

Normally you can serialize your class and desterilized but if the data
needs
to be in a compact byte array which I have found need for several times
you
will need to parse the data manually. I think you can overload the
serialization function but I have found the below simpler.

Note that for your solution, the line

ms.Capacity = ms.Length;

is unnecessary.

Personally, I'd prefer to create the 6 byte array to start with, and
then populate it. The "standard" BitConverter doesn't have any way to
convert into the middle of an existing array, but my own one does :)

See http://www.pobox.com/~skeet/csharp/miscutil and the
EndianBitConverter class.

In this case, the code might be (converting it to a method rather than
a property);

public byte[] ToArray()
{
EndianBitConverter converter = EndianBitConverter.Little;
byte[] ret = new byte[6];
converter.CopyBytes (val1, ret, 0);
converter.CopyBytes (val2, ret, 2);
converter.CopyBytes (val3, ret, 4);
return ret;
}

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Oct 23 '06 #9
O.B. wrote:
I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?
O.B.,

The other guys have explained quite well why you can't do it; and why you
shouldn't do it. You've got to remember C# is a managed programming
language, it doesn't usually have access to raw memory and the same types
of clevery you can do with C++, et al.

However, this is how you do it:

Firstly, define your TestA as a struct, and give it the attribute of
LayoutKind.Sequential:

///
[StructLayout(LayoutKind.Sequential)]
public struct TestA
{
public ushort val1;
public ushort val2;
public ushort val3;
}
///

Then your new test method should read:

///
static void Main( string[] args )
{
TestA test;

byte[] testArray = new byte[6];
for ( int i = 0; i < testArray.Length; i++ )
testArray[i] = (byte)(i + 1);

IntPtr arrayPtr = Marshal.UnsafeAddrOfPinnedArrayElement( testArray, 0 );
test = (TestA) Marshal.PtrToStructure( p, typeof( TestA ) );
}
///

So, the start of the code is the same (loading your array), then the next
two lines perform the magic. The first gets a pointer to the start of the
byte array, and stores it in arrayPtr. The second then generates the
structure, given that pointer and the type of structure being generated.

--
Hope this helps,
Tom Spink

Google first, ask later.
Oct 23 '06 #10
Tom Spink wrote:
O.B. wrote:
>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?

O.B.,

The other guys have explained quite well why you can't do it; and why you
shouldn't do it. You've got to remember C# is a managed programming
language, it doesn't usually have access to raw memory and the same types
of clevery you can do with C++, et al.

However, this is how you do it:

Firstly, define your TestA as a struct, and give it the attribute of
LayoutKind.Sequential:

///
[StructLayout(LayoutKind.Sequential)]
public struct TestA
{
public ushort val1;
public ushort val2;
public ushort val3;
}
///

Then your new test method should read:

///
static void Main( string[] args )
{
TestA test;

byte[] testArray = new byte[6];
for ( int i = 0; i < testArray.Length; i++ )
testArray[i] = (byte)(i + 1);

IntPtr arrayPtr = Marshal.UnsafeAddrOfPinnedArrayElement( testArray, 0
); test = (TestA) Marshal.PtrToStructure( p, typeof( TestA ) );
}
///

So, the start of the code is the same (loading your array), then the next
two lines perform the magic. The first gets a pointer to the start of the
byte array, and stores it in arrayPtr. The second then generates the
structure, given that pointer and the type of structure being generated.
I made a slight error while I was touch-typing from monitor 1, to monitor 2:

On the line of code that is PtrToStructure, I left the first parameter as p,
when in fact it should be arrayPtr. Appologies.

--
Hope this helps,
Tom Spink

Google first, ask later.
Oct 23 '06 #11
I don't understand why you are coping the data from one array to another,
just use the array the UdpClient is giving you.

Personally I normally use socket and have found the socket can not give you
data as fast as you can process it so you will be spending more time idle
anyway so you might be trying to optimize something more then needed.

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
This is *real* close to what I want. The only drawback is that I'm having
to instantiate new memory for the TestA structure before calling Marshal.
The UdpClient is already returning an allocated byte array. This
application has to run as close to real-time as possible.

TestA test;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
Marshal.Copy(testArray, 0, (IntPtr)(&test), 6);

John J. Hughes II wrote:
>Oh by the way if you convert to a structure and set the offsets manually
you can then do a memory copy to accomplish what you did in C.

Sort of like this, don't do it as often so a little fuzzer on how.

[StructLayout(LayoutKind.Explicit)]
public struct TestA
{
[FieldOffset(0)] public ushort Val1;
[FieldOffset(2)] public ushort Val2;
[FieldOffset(4)] public ushort Val2;
}

Marshal.Copy(Data, 0, IntPtr <TestA>, 6);

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
>>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?
Oct 23 '06 #12

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
This is *real* close to what I want. The only drawback is that I'm having
to instantiate new memory for the TestA structure before calling Marshal.
The UdpClient is already returning an allocated byte array. This
application has to run as close to real-time as possible.
This whole business breaks all type-safety rules (only the BitConverter
method was type-safe).

If that's ok with you, and it sounds like it is, then use explicit layout
and pointers inside an unsafe block.

>
TestA test;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
Marshal.Copy(testArray, 0, (IntPtr)(&test), 6);

John J. Hughes II wrote:
>Oh by the way if you convert to a structure and set the offsets manually
you can then do a memory copy to accomplish what you did in C.

Sort of like this, don't do it as often so a little fuzzer on how.

[StructLayout(LayoutKind.Explicit)]
public struct TestA
{
[FieldOffset(0)] public ushort Val1;
[FieldOffset(2)] public ushort Val2;
[FieldOffset(4)] public ushort Val2;
}

Marshal.Copy(Data, 0, IntPtr <TestA>, 6);

Regards,
John

"O.B." <fu******@bellsouth.netwrote in message
news:12*************@corp.supernews.com...
>>I'm trying to do a static_cast at runtime in C# and as I understand it,
"as" is the keyword to use. Unfortunately, the compiler is trying to do
the cast a compilation time. See below.

/* TestA.cs */
namespace TEST {
class TestA {
public ushort val1;
public ushort val2;
public ushort val3;
}
}

/* Main Program */
namespace TEST {
class Program {
static void Main(string[] args) {
TestA test = null;
byte[] testArray = new byte[6];
for (int i = 0; i < testArray.Length; i++) {
testArray[i] = (byte)(i + 1);
}
// Trying to do a C++-style static_cast
// Compilation error:
// Cannot convert type 'byte[]' to 'TEST.TestA'
// via a built-in conversion
test = testArray as TestA;
}
}
}

What am I doing wrong?
Oct 23 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Jacob Jensen | last post: by
4 posts views Thread by vertigo | last post: by
4 posts views Thread by Harry | last post: by
28 posts views Thread by Tamir Khason | last post: by
7 posts views Thread by The Last Gunslinger | last post: by
61 posts views Thread by Ken Allen | last post: by
6 posts views Thread by AMP | last post: by
1 post views Thread by Waqarahmed | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.