添加到可变类型中,就好像它是不可变的一样(有序地)

本文关键字:不可变 一样 类型 添加 | 更新日期: 2023-09-27 18:20:42

我正在表单上构建一个对象:

return table.Rows.Cast<DataRow>()
  .Select(row => new Something
  {
    Field = row["field1"] as int?,
    Bunch = GetBunch(index)
  });

使用GetBunch(),如下所示。

private IList GetBunch(int index) { ... }

它按预期工作。现在,我们注意到,我们需要向放入Bunch的数组添加一个额外的元素。由于各种原因,更改方法的签名是不可行的,在其中添加额外的元素也是不可行的

我试着添加额外的东西:

return table.Rows.Cast<DataRow>()
  .Select(row => new Something
  {
    Field = row["field1"] as int?,
    Bunch = GetBunch(index).Add(new Thingy() { ... })
  });

但它没有工作,因为Add()没有返回包含新元素的原始数组。它返回了一个int。如果原始对象是不可变的,那么Add()的结果将是我所希望的,但显然不是。

有可能使可变对象免疫吗?如果不是(因为我很确定不是),我该如何轻松处理?(很容易=无需存储创建的东西,然后访问它并将元素添加到Bunch属性的数组中。)

注意,在这种情况下,结果的顺序并不重要。合适的类型是某种类型的袋子,但我被预先存在的设计束缚住了手脚。

添加到可变类型中,就好像它是不可变的一样(有序地)

可能是这样的东西:

return table.Rows.Cast<DataRow>()
.Select(row => {
                  var list = GetBunch(index);
                  list.Add(new Thingy() { ... });
                  return new SomeThing 
                         {
                            Field = row["field1"] as int?,
                            Bunch = list
                         };
                });

正如@Chris在评论中指出的那样,您可以使用lambda语句,而不一定需要使用lamda表达式。您可以在块内部执行任何您想要的操作,因为它只是一个接受DataRow并返回SomeThing的方法。

好的Selman22的答案的替代方案:创建一个助手扩展方法,它可以让您添加到GetBunch()的结果中,而无需将其封装在lambda内联中:

static class MyListExtenstions
{
  static IList AddToList<T>(this IList list, T item)
  {
    list.Add(item);
    return list;
  }
}

并在线使用:

return table.Rows.Cast<DataRow>()
  .Select(row => new Something
     {
         Field = row["field1"] as int?,
         Bunch = GetBunch(index).AddToList(new Thingy() { ... })
     });

还有一种LINQ方法,它可以创建更多的中间对象,但可以处理不可变的(意味着添加项会引发异常)列表:

如果您想要一个可以用于链接的方法,您可以使用IEnumerable<T>.Concat()(在您的情况下,可以使用.ToList())。这种方法将为您提供新的列表,如果GetBunch的结果是:,则会很有用

 GetBunch(index)
    .Concat(Enumerable.Repeat(new Thingy() { ... }, 1))
    .ToList()

注意:如果您的GetBunch将返回泛型IList<T>IEnumerable<T>,则可以使用Enumerable的辅助方法(如.Concat())。由于它返回非通用版本,您需要使用Enumerable.Cast之类的东西将其转换为通用变体,或者转换为通用接口以使用LINQ方法。您需要知道实际类型是什么,或者应该返回什么类型的项。

 GetBunch(index).Cast<object>()
 GetBunch(index) as IList<Thingy> 
return table.Rows.Cast<DataRow>()
    .Select(row => new Something
    {
        Field = row["field1"] as int?,
        Bunch = GetBunch(index).Union(x => 
            new[] { new Thingy() { ... } }
            ).ToList()
    });