简体   繁体   中英

How can I make my own method into a chainable LINQ method?

I have code like this, which builds data to a specific format from an input collection, and appends a checksum value:

        var data = input.Aggregate(new List<byte>(), (list, item) =>
        {
            list.Add(item.x);
            list.Add(item.y);
            list.Add(item.bytes.Length);
            list.AddRange(item.bytes);
        });
        data.Add(Checksum(data));
        var bytes = data.ToArray();

I interested to make this a single line but I cannot see how I can chain data into Checksum() which currently has the signature byte Checksum(IEnumerable<byte> input) .

I thought I could do something like:

        IEnumerable<byte> AddCheckSum(IList<byte> input)
        {
         return input.Add(Checksum(input));
        }

        var data = input.Aggregate(new List<byte>(), (list, item) =>
        {
            list.Add(item.x);
            list.Add(item.y);
            list.Add(item.bytes.Length);
            list.AddRange(item.bytes);
        }).AddChecksum().ToArray();

But I can't figure out how. Is it straighforward?

I doubt if you want Aggregate at all; Linq seems to be more compact readable with SelectMany and Concat :

var data = input
  .SelectMany(item => new byte[] {item.x, item.y, item.bytes.Length}.Concat(item.bytes));

var bytes = data
  .Concat(new byte[] {Checksum(data)})
  .ToArray();

but I suggest foreach solution with explicit List<byte> data :

List<byte> data = new List<byte>();

foreach (var item in input) {
  data.Add(item.x);
  data.Add(item.y);
  data.Add(item.bytes.Length);
  data.AddRange(item.bytes);
} 

data.Add(Checksum(data));

var bytes = data.ToArray();

Finally, if you want to compute the fragment in one go, you can wrap it into an extension method :

public static class MyInputExtensions {
  public static byte[] ToBytesWithCheckSum(this IEnumerable<MyInput> input) {
    if (null == input)
      throw new ArgumentNullException(nameof(input));  

    List<byte> data = new List<byte>();

    foreach (var item in input) {
      data.Add(item.x);
      data.Add(item.y);
      data.Add(item.bytes.Length);
      data.AddRange(item.bytes);
    }      

    data.Add(Checksum(data));

    return data.ToArray(); 
  }
}

then you can use ToBytesWithCheckSum() as if it's a method of input collection:

 byte[] bytes = input.ToBytesWithCheckSum();

Use extension method.

public static class AddChecksumHelpers
{
    public static IEnumerable<byte> AddCheckSum(this IEnumerable<byte> input)
    {
        return input.Concat(new[] { CheckSum(input) });
    }
}

Or you could take and return List<byte> if you have data in that format and directly return the input list (after calling .Add(CheckSum(input)) ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM