A portion of long data bytes as a property

S

Sin Jeong-hun

Here are my imaginary codes:

void DoSomething()
{
FileStream fs;
Packet p;
...
fs.Write(p.Body, 0, p.Body.Length);
}

class Packet
{
byte[] EntireData;
....
public Body
{
get
{
byte[] rtn = new byte[EntireSize - HeaderSize];
Array.Copy(EntireData, HeaderSize, rtn, BodySize);
return rtn;
}
}
}

When we write the body of the packet to a file inside DoSomething, we
just want to read the content of the Body. But I guess this code is
very inefficient because it makes another copy of the long data. If I
was using C, I could just return the address by adding HeaderSize to
the pointer to the EntireData.

How could I make the Packet class above more efficient? Any
suggestions would be welcome. Thank you.
 
P

Peter Duniho

Sin said:
Here are my imaginary codes:

void DoSomething()
{
FileStream fs;
Packet p;
...
fs.Write(p.Body, 0, p.Body.Length);
}

class Packet
{
byte[] EntireData;
....
public Body
{
get
{
byte[] rtn = new byte[EntireSize - HeaderSize];
Array.Copy(EntireData, HeaderSize, rtn, BodySize);
return rtn;
}
}
}

When we write the body of the packet to a file inside DoSomething, we
just want to read the content of the Body. But I guess this code is
very inefficient because it makes another copy of the long data. If I
was using C, I could just return the address by adding HeaderSize to
the pointer to the EntireData.

How could I make the Packet class above more efficient? Any
suggestions would be welcome. Thank you.

Hard to say without more context. But one possible approach would be to
delegate the writing to the Packet class itself:

void DoSomething()
{
FileStream fs;
Packet p;
...
p.WriteBody(fs);
}

class Packet
{
byte[] EntireData;
....

public void WriteBody(Stream stream)
{
stream.Write(EntireBody, HeaderSize, EntireSize - HeaderSize);
}

public byte[] Body
{
get
{
byte[] rtn = new byte[EntireSize - HeaderSize];
Array.Copy(EntireData, HeaderSize, rtn, BodySize);
return rtn;
}
}
}

Pete
 
P

Peter Duniho

Peter said:
[...]
public void WriteBody(Stream stream)
{
stream.Write(EntireBody, HeaderSize, EntireSize - HeaderSize);
}

Sorry, that should be "EntireData", not "EntireBody", of course.
 
S

Sin Jeong-hun

Peter said:
[...]
   public void WriteBody(Stream stream)
   {
       stream.Write(EntireBody, HeaderSize, EntireSize - HeaderSize);
   }

Sorry, that should be "EntireData", not "EntireBody", of course.

Thanks, but " fs.Write(p.Body, 0, p.Body.Length);" was just an
example. I don't know what class will use the "Body" property. Isn't
there any way to make a "virtual" read-only copy (that doesn't
actually take memory) of the portion of the large byte array
(=EntireData)? In the original code I wrote, it would be very
inefficient because every time "Body" is accessed a new copy will be
created.

class Packet
{
private:
char EntireData[1024];
public:
const char* GetBody()
{
int HeaderLength=12;
return EntireData+HeaderLength;
}
};

Like this C++ code. Getting Body doesn't involve any copying.
 
P

Peter Duniho

Sin said:
[...] In the original code I wrote, it would be very
inefficient because every time "Body" is accessed a new copy will be
created.

Define "very inefficient". Inefficient compared to what? Creating an
impact to what degree in the rest of the code?
class Packet
{
private:
char EntireData[1024];
public:
const char* GetBody()
{
int HeaderLength=12;
return EntireData+HeaderLength;
}
};

Like this C++ code. Getting Body doesn't involve any copying.

That's true. But it also exposes implementation detail to client code,
making it that much more convenient to shoot yourself in the foot.

Short answer: no, you can't do this in C#.

Slightly longer answer: copying the array isn't really that big of a
problem most of the time; usually that copy is going to be sent off
somewhere that is WAY slower than memory access. You could copy the
array in memory a dozen, maybe even a hundred times, before the overhead
becomes noticeable.

There are exceptions to every rule, of course. But for most purposes
it's true.

Note that if performance really is a big concern, you may prefer to use
the Buffer.BlockCopy() method instead of Array.Copy(). It doesn't do as
much validation on the operation, copying raw bytes from one place to
the other (even though it can handle any type of array), and so is
somewhat faster.

That said, here's a slight variation on what I posted earlier that might
work for you:

void DoSomething()
{
FileStream fs;
Packet p;
...
p.UseBody((byte[] rgb, int ibFirst, int cbLength) =>
fs.Write(rgb, ibFirst, cbLength));
}

class Packet
{
byte[] EntireData;
....

public void UseBody(Action<byte[], int, int> actionUse)
{
actionUse(EntireBody, HeaderSize, EntireSize - HeaderSize);
}

public byte[] Body
{
get
{
byte[] rtn = new byte[EntireSize - HeaderSize];
Array.Copy(EntireData, HeaderSize, rtn, BodySize);
return rtn;
}
}
}

That of course exposes implementation details, as your proposed C/C++
variant would. But, it avoids the client having to query three
different properties, or pass local variables to some method that
returns three different values.

Note that whether you return the byte[] reference to the caller, or you
pass it to a delegate the caller provides, you can improve your
encapsulation by returning/passing not the byte[] itself, but the result
of calling AsReadOnly() on the byte[]. Of course, this is only useful
if you don't literally need a byte[]; if you're writing the bytes to a
Stream of some sort, for example, then that's probably not going to work
for you. I mention it only if it should come up in other situations
where it would be feasible.

Pete
 
S

Sin Jeong-hun

Sin said:
[...] In the original code I wrote, it would be very
inefficient because every time "Body" is accessed a new copy will be
created.

Define "very inefficient".  Inefficient compared to what?  Creating an
impact to what degree in the rest of the code?
class Packet
{
private:
    char EntireData[1024];
public:
    const char* GetBody()
    {
        int HeaderLength=12;
        return EntireData+HeaderLength;
    }
};
Like this C++ code. Getting Body doesn't involve any copying.

That's true.  But it also exposes implementation detail to client code,
making it that much more convenient to shoot yourself in the foot.

Short answer: no, you can't do this in C#.

Slightly longer answer: copying the array isn't really that big of a
problem most of the time; usually that copy is going to be sent off
somewhere that is WAY slower than memory access.  You could copy the
array in memory a dozen, maybe even a hundred times, before the overhead
becomes noticeable.

There are exceptions to every rule, of course.  But for most purposes
it's true.

Note that if performance really is a big concern, you may prefer to use
the Buffer.BlockCopy() method instead of Array.Copy().  It doesn't do as
much validation on the operation, copying raw bytes from one place to
the other (even though it can handle any type of array), and so is
somewhat faster.

That said, here's a slight variation on what I posted earlier that might
work for you:

void DoSomething()
{
    FileStream fs;
    Packet p;
    ...
    p.UseBody((byte[] rgb, int ibFirst, int cbLength) =>
       fs.Write(rgb, ibFirst, cbLength));

}

class Packet
{
    byte[] EntireData;
    ....

    public void UseBody(Action<byte[], int, int> actionUse)
    {
        actionUse(EntireBody, HeaderSize, EntireSize - HeaderSize);
    }

    public byte[] Body
    {
       get
       {
          byte[] rtn = new byte[EntireSize - HeaderSize];
          Array.Copy(EntireData, HeaderSize, rtn, BodySize);
          return rtn;
       }
    }

}

That of course exposes implementation details, as your proposed C/C++
variant would.  But, it avoids the client having to query three
different properties, or pass local variables to some method that
returns three different values.

Note that whether you return the byte[] reference to the caller, or you
pass it to a delegate the caller provides, you can improve your
encapsulation by returning/passing not the byte[] itself, but the result
of calling AsReadOnly() on the byte[].  Of course, this is only useful
if you don't literally need a byte[]; if you're writing the bytes to a
Stream of some sort, for example, then that's probably not going to work
for you.  I mention it only if it should come up in other situations
where it would be feasible.

Pete

Thank you for your long explanation. I also thought of the
encapsulation. Returning a copy of the portion of the EntireData would
be the safest and OOP way, but I was wondering if there were any more
efficient or better way to do that because the Body property is
accessed very often (because there are many Packets) I'll think over
your codes. And thank you also for Buffer.BlockCopy. At least I could
use it instead of Array.Copy.
 
N

not_a_commie

WCF uses an ArraySegment<byte> class which wraps up an array and adds
current Position and Count properties to it. You have to deal with
that class if you overload MessageEncoder. I'm sure you could use it
separately from WCF. It works quite well. I also think that it's okay
to have a "write body to stream" method on your class where you pass
in the destination stream.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top