-1

Is there a better way to convert a ListArray into a byte array in C#? The ListArray is coming from a dictionary object and contains a ListArray of objects where the underlying type is int. The only way I could get it to work was by looping thru the ListArray and individually inserting into the byte array. I was trying to get it to work with ToArray but I kept getting a cast error.

static void Main(string[] args)
{
    int intLoop;
    byte[] arrByte;
    string strJson = "{\"Data\":[104,101,108,108,111,32,119,111,114,108,100]}";
    Dictionary<string, object> dic = new Dictionary<string, object>();
    JavaScriptSerializer js = new JavaScriptSerializer();

    //deserialize json into dictionary object
    dic = js.Deserialize<Dictionary<string, object>>(strJson);

    //convert arraylist into byte array
    intLoop = 0;
    arrByte = new byte[((System.Collections.ArrayList)dic["Data"]).Count];
    foreach (var s in (System.Collections.ArrayList)dic["Data"])
    {
        arrByte[intLoop] = Convert.ToByte(s);
        intLoop++;
    }

}
Madison320
  • 247
  • 3
  • 11
  • JSON deserialization is built-in to the framework (at least if you're using .NET Core / .NET 5+), no need to use this legacy API. Also, the correct way to use it would be to create a model with a `Data` property of type `List`. https://learn.microsoft.com/en-us/dotnet/api/system.web.script.serialization.javascriptserializer?view=netframework-4.8 – silkfire Jul 21 '21 at 14:23
  • Any particular reason *why* you want to use `ArrayList`? It really shouldn;t be used anymore – Charlieface Jul 21 '21 at 22:02

3 Answers3

2

There's nothing wrong with your approach, but, if you prefer, you could use a LINQ one-liner instead:

ArrayList data = ...;

var arrByte = data.Cast<int>().Select(i => (byte)i).ToArray();

Note: Cast<int>() is required because your code uses the legacy ArrayList type. If your source type already implements IEnumerable<int> (for example, a List<int> or an int[]), you can skip this step.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • Sorry your answer gives only 11 bytes(the same is array length) , mine is 72. I guess because all number are less than 256. I don' t know which is true, trying to make some research – Serge Jul 21 '21 at 14:35
  • If you try this array var data= [104,101,108,108,111,32,119,111,114,308,300] you will see very strange result. – Serge Jul 21 '21 at 14:44
  • @Serge: I believe it's because you used `BinaryFormatter`, which dumps type information, field names and object ids into the stream. When using generic types the overhead can be really [brutal](https://dotnetfiddle.net/T7BUyB). – György Kőszeg Jul 21 '21 at 14:45
  • @GyörgyKőszeg I think the question is not correct. byte[]=int[] when all numbers are less 255. After this we will see an an overflow in one of the number are bigger 255 – Serge Jul 21 '21 at 14:48
  • 1
    This data is coming from a file that has been converted to a byte array so the data should always be less than 256. – Madison320 Jul 21 '21 at 14:51
  • @Heinzi That works, I'm impressed by anyone who can figure out linq syntax. Thanks! – Madison320 Jul 21 '21 at 14:53
  • @Heinzi I wonder why the dictonary object uses the ArrayList in this case? – Madison320 Jul 21 '21 at 14:55
  • @Madison320: Because `JavaScriptSerializer` is a legacy API from the old days when dinosaurs roamed the earth (ok, maybe not that old, but close). Back in those dark days, we didn't have generic lists, and now they can't change the behavior of JavaScriptSerializer because that would break backwards compatibility. If you can, use Newtonsoft.Json (or the new Json classes from .NET 5+) instead. – Heinzi Jul 21 '21 at 15:09
  • 1
    @Heinzi Hey, I had a pet dinosaur. I'm going to upgrade right now. Thanks! – Madison320 Jul 21 '21 at 15:17
1

The problem is that int[] and byte[] are the same when all numbers are less 255. If one of the numbers is large than 255 it will throw exeption during conversion.

If you need byte[]

string strJson = "{\"Data\":[104,101,108,108,111,32,119,111,114,108,100]}";

var byteArray = JsonConvert.DeserializeObject<RootData>(strJson);

class

public class RootData
{
    public byte[] Data {get; set;}
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • +1 for using an object model instead of just serializing to a dictionary. I wonder if this can be simplified by declaring `Data` directly as `byte[]` (and skipping all the conversion stuff)... – Heinzi Jul 21 '21 at 14:28
  • @Heinzi Thanks, I added your answer to mine, if you don't mind – Serge Jul 21 '21 at 14:29
  • In my case I'm probably stuck using the dictionary. I simplified my example but in reality there are many more data entries of different types in my actual dictionary object. – Madison320 Jul 21 '21 at 14:37
  • Are you sure you want to recommend using `BinaryFormatter`? It is planned to be [removed](https://github.com/dotnet/designs/blob/main/accepted/2020/better-obsoletion/binaryformatter-obsoletion.md) from .NET due to its [security flaws](https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide). Once I collected some of the mayor issues in [this](https://stackoverflow.com/a/67107584/5114784) answer. – György Kőszeg Jul 21 '21 at 14:50
  • I know this, but the problem is what PO wants. You int[] and byte[] are the same when all numbers are less 255. If one of the numbers is large than 255 it should throw exeption. – Serge Jul 21 '21 at 14:53
0

That's how I would write it (using c# 9 language features)

public record MyDto(IEnumerable<int> Data);


var json = "{\"Data\":[104,101,108,108,111,32,119,111,114,108,100]}";
var document = JsonSerializer.Deserialize<MyDto>(json);
var bytes = document?.Data
        .Select(i => (byte) i)
        .ToArray();
  1. Create data structure to represent the input data
  2. Parse it with System.Text.Json JsonSerializer (the new standard json serializer)
  3. Convert it with LINQ
Christoph Lütjen
  • 5,403
  • 2
  • 24
  • 33
  • I'll have to check out that json serializer. I was just using the first one I found. :) – Madison320 Jul 21 '21 at 14:59
  • I thought "better way" may include "do not use legacy components" ;-) – Christoph Lütjen Jul 21 '21 at 15:18
  • int[] and byte[] are the same when all numbers are less 255. If one of the numbers is large than 255 it should throw exeption. So you don' t need any select, just change IEnumerable – Serge Jul 21 '21 at 15:19
  • `IList<>` would break immutability of the dto, so I'd use `IEnumerable` instead. But one could argue that the correct representation of the json is a collection of numbers and the requirement to convert this to bytes comes later. Or it's 1:1 and directly deserializing to the final type is the better approach. I think `IEnumerable` is the better solution here but I didn't test it that's why I don't update the answer. – Christoph Lütjen Jul 21 '21 at 15:28