首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何巧妙地从IEnumerable<T>创建匿名类型?

如何巧妙地从IEnumerable<T>创建匿名类型?
EN

Stack Overflow用户
提问于 2012-03-22 05:58:43
回答 6查看 4.1K关注 0票数 4

我想用LINQ来解决以下问题,我有以下几个集合:

代码语言:javascript
复制
List<byte> byteList = new List<byte() { 0x01, 0x00, 0x01, 0x02, 0x01, 0x00, 0x3, 0x4, 0x02 };

此示例中的数据遵循以下模式:

byteList =地址(1,2,3,...n)

byteList1 =旧状态,基本上代表枚举

byteList2 =新状态,同上

我正在与一个嵌入式设备交互,这就是我可以查看输入更改的方式。

为了清理代码并使维护程序员更容易理解我的逻辑,我想抽象出一些涉及的细节,并将每个三字节的数据集提取为一个匿名类型,以便在函数中使用,以执行一些额外的处理。我已经写了一个快速实现,但我相信它可以大大简化。我在试着清理代码,而不是混水摸鱼!必须有一种更简单的方法来完成以下操作:

代码语言:javascript
复制
List<byte> byteList = new List<byte>()
{
    0x01, 0x09, 0x01, 0x02, 0x08, 0x02, 0x03, 0x07, 0x03
};
var addresses = byteList
    .Where((b, i) => i % 3 == 0)
    .ToList();
var oldValues = byteList
    .Where((b, i) => i % 3 == 1)
    .ToList();
var newValues = byteList
    .Where((b, i) => i % 3 == 2)
    .ToList();

var completeObjects = addresses
    .Select((address, index) => new 
    { 
        Address = address,
        OldValue = oldValues[index],
        NewValue = newValues[index]
    })
    .ToList();
foreach (var anonType in completeObjects)
{
    Console.WriteLine("Address: {0}\nOld Value: {1}\nNew Value: {2}\n",
        anonType.Address, anonType.OldValue, anonType.NewValue);
}
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-03-22 06:15:01

你可以使用Enumerable.Range和一些数学:

代码语言:javascript
复制
List<byte> byteList = new List<byte>()
{
    0x01, 0x09, 0x01, 0x02, 0x08, 0x02, 0x03, 0x07, 0x03
};
var completeObjects = Enumerable.Range(0, byteList.Count / 3).Select(index =>
    new
    {
        Address = byteList[index * 3],
        OldValue = byteList[index * 3 + 1],
        NewValue = byteList[index * 3 + 2],
    });

如果字节数不是3的倍数,则会忽略多余的一到两个字节。

票数 5
EN

Stack Overflow用户

发布于 2012-03-22 06:07:41

为简化起见,我将创建一个record类型并使用for循环:

代码语言:javascript
复制
class RecordType
{
    //constructor to set the properties omitted
    public byte Address { get; private set; }
    public byte OldValue { get; private set; }
    public byte NewValue { get; private set; }
}

IEnumerable<RecordType> Transform(List<byte> bytes)
{
    //validation that bytes.Count is divisible by 3 omitted

    for (int index = 0; index < bytes.Count; index += 3)
        yield return new RecordType(bytes[index], bytes[index + 1], bytes[index + 2]);
}

或者,如果您确实需要匿名类型,则可以不使用linq:

代码语言:javascript
复制
for (int index = 0; index < bytes.Count; index += 3)
{
    var anon = new { Address = bytes[index], OldValue = bytes[index + 1], NewValue = bytes[index + 3] };
    //... do something with anon
}

Linq非常有用,但它在这项任务中很笨拙,因为序列项根据它们在序列中的位置具有不同的含义。

票数 3
EN

Stack Overflow用户

发布于 2012-03-22 06:15:04

我不确定这是不是一个聪明的解决方案,但我使用了这个示例来尝试在不创建单独列表的情况下实现这一点。

代码语言:javascript
复制
var completeObjects = byteList
    // This is required to access the index, and use integer
    // division (to ignore any reminders) to group them into
    // sets by three bytes in each.
    .Select((value, idx) => new { group = idx / 3, value })
    .GroupBy(x => x.group, x => x.value)

    // This is just to be able to access them using indices.
    .Select(x => x.ToArray())

    // This is a superfluous comment.
    .Select(x => new {
        Address = x[0],
        OldValue = x[1],
        NewValue = x[2]
    })

    .ToList();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9813499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档