Reputation: 13575
I have a function which will take some byte(s) OR byte[] and bundle them all up in a byte[] and return. I placed my choice on params keyword in c# but not sure how to make it accept both individual byte(s) and byte[] both as parameters:
my sample code below:
public byte[] Construct(params byte[] values)
{
List<byte> packet = new List<byte>();
for (int i = 0; i < values.Length; i++)
{
packet.Add(values[i]);
}
return packet.ToArray();
}
Please not that construct should be able to accept both individual byte(s) and byte[]
Any suggestions?
Upvotes: 1
Views: 94
Reputation: 5944
An alternative is to let the functions argument be params byte[][]
.
Then if you would have to pass a single byte you could pass it as an array of length one.
LinqPad example:
void Main()
{
Construct(new byte[] { 10, 20 }, new byte[] { 255 }).Dump();
}
public byte[] Construct(params byte[][] values)
{
return values.SelectMany(x => x).ToArray();
}
Here 255
is a single byte, but 'wrapped' in an array.
This prints the following:
10
20
255
Upvotes: 1
Reputation: 101681
params
should be the last parameter in the method definition, like this:
public byte[] Construct(byte arg1, byte arg2, params byte[] values)
From documentation:
No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration.
If you want to pass one byte array, then individual bytes after that array you can use this signature:
public byte[] Construct(byte[] array, params byte[] values)
This version expects at least one byte array and then one or more bytes.For example you can call it like this, just with byte array:
Construct(new byte[] { 10,20,30,40 });
Or like this, all of them are valid:
Construct(new byte[] { 10,20,30,40 }, 11);
Construct(new byte[] { 10,20,30,40 }, 11,22,33);
Construct(new byte[] { 10,20,30,40 }, 11,22,33,44);
Construct(new byte[] { 10,20,30,40 }, new byte[] { 11,22,33,44 });
But this is not valid:
Construct(new byte[] { 10,20}, new byte[] { 11,22 }, 77);
Because first parameter is byte
array, second is params
.And there is no third parameter.So basically params byte[]
means: zero
or more
bytes, or just one byte array.
Upvotes: 1
Reputation: 754585
Note that if you want a method that will accept individual byte
values and a single byte[]
then your current definition is already sufficient.
Construct(42, 13); // Works
Construct(new byte[] { 42, 13 }); // Also works
If you want to accept both byte[]
and byte
values into the same method call then you will need to add overloads to accommodate that.
byte[] Construct(byte b1, byte[] b2)
byte[] Construct(byte b1, byte b2, byte[] b3)
// etc ...
Other than that the only issue with the current definition is that it's unnecessarily allocation heavy.
Firstly the method body inefficiently allocates array values. The List<byte>
type is going to dynamically allocate byte[]
values as they are added. After all those allocations are done another final byte[]
will be allocated in the ToArray
call. In this particular case you know the exact size of the final array hence it's more efficient to just allocate it directly and avoid List<byte>
byte[] packet = new byte[values.Length];
for (int i = 0; i < values.Length; i++) {
packet[i] = values[i];
}
return packet;
The second inefficiency is that the calling code will allocate an array for passing a relatively small number of parameters. If this is actually common then you can avoid the array allocation by having non-params overloads
public byte[] Construct(byte b1) {
return new[] { b1 };
}
public byte[] Construct(byte b1, byte b2) {
return new[] { b1, b2 };
}
Upvotes: 1