Pergunta

I have a binary serialized object in memory and I want to read it from memory by using pointers (unsafae code) in C#. Please look at the following function which is reading from memory stream.

static Results ReadUsingPointers(byte[] data)
{
    unsafe
    {
        fixed (byte* packet = &data[0])
        {
            return *(Results*)packet;
        }
    }
}

At this return *(Results*)packet; statement i get a compile time exception "Cannot take the address of, get the size of, or declare a pointer to a managed type Results"

Here is my structure

public struct Results
{
    public int Id;
    public int Score;
    public char[] Product;
}

As per my understanding, all properties of my struct are blittable properties, then why I am getting this error, and what should I do if I need to use char[] in my structure?

EDIT-1 Let me explain further (plz note that the objects are mocked)...

Background: I have an array of Results objects, I serialized them using binary serialization. Now, at later stages of my program, I need to de-serialize my data in memory as quickly as possible as the data volume is very large. So I was trying, how unsafe code can help me there.

Lets say if my structure don't include public char[] Product;, I get my data back at reasonably good speed. But with char[] it gives me error(compiler should do so). I was looking to find out a solution that work with char[] in this context.

Foi útil?

Solução 2

You cannot expect that to work.

public struct Results
{
    public int Id;
    public int Score;
    public char[] Product;
}

The char[] array Product is a managed type. Your code attempts to use the type Results*. That is a pointer type. The documentation states that you can declared pointers to any of the following:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
  • Any enum type.
  • Any pointer type.
  • Any user-defined struct type that contains fields of unmanaged types only.

Now, your struct clearly matches none of the first three bullets. And does not match the final bullet either because the array is a managed type.

As per my understanding, all properties of my struct are blittable properties.

Yes that is true, but not relevant. You need the members of the struct to be more than blittable.


Even if your code would compile, how would you imagine that it could work? Consider this expression:

*(Results*)packet

How could the compiler turn that into something that would create a new array and copy the correct number of elements of the array? So clearly the compiler has no hope of doing anything useful here and that of course is why the language rejects your code.

I don't think that unsafe code is going to help you here. When you serialize your array you will have to serialize the length, and then the array's content. To deserialize you need to read the length, create a new array of that length, and then read the content. Unsafe code cannot help with that. A simple memory copy of a statically defined type is no use because that would imply that the array's length was known at compile time. It is not.


Regarding your update, you said:

I have an array of Results objects which I serialized using binary serialization.

In order to deserialize you need code that understands the detailed layout of your binary serialization. The code in the question cannot do it.

What you perhaps have not understood yet is that you cannot expect to copy arbitrary blocks of memory, whose lengths are variable and only known at runtime, without something actually knowing those lengths. In effect you are hoping to be able to copy memory without anything in the system knowing how much to copy.

Your attempts to deserialize using an unsafe typecast and memory copy cannot work. You cannot expect any more detailed help without consideration of the binary format of your serialization.

Outras dicas

MSDN says:

Any of the following types may be a pointer type:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.

  • Any enum type.

  • Any pointer type.

  • Any user-defined struct type that contains fields of unmanaged types only.

So you could define your struct as follows to fix the compiler error:

public struct Results
{
    public int Id;
    public int Score;
    // Don't actually do this though.
    public unsafe char* Product;
}

This way, you can point to the first element of an array.

However, based on your edited question, you need a different approach here.

I have an array of Results objects, I serialized them using binary serialization. Now, at later stages of my program, I need to de-serialize my data in memory as quickly as possible

Usually you would use BinaryFormatter for that purpose. If that is too slow, the question should rather be if serialization can be avoided in the first place.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top