简体   繁体   English

更改可枚举集合中的对象

[英]Change objects in an enumerable collection

I have a collection that cannot be iterated through (via index), but it does implement IEnumerable . 我有一个不能通过(通过索引)进行迭代的集合,但是它确实实现了IEnumerable

Is there a way to replace objects in that collection when enumerating though it? 枚举时是否可以替换该集合中的对象? I know that this is not possible in a foreach loop, but it seems like a reasonable thing to want to do. 我知道这在foreach循环中是不可能的,但是似乎很想做。

I went so far as to consider using C#'s pointers, but those don't work with managed types. 我曾经考虑使用C#的指针,但那些不适用于托管类型。

I know that I can populate an array with all of the data, and then edit it that way, but 我知道我可以用所有数据填充数组,然后以这种方式进行编辑,但是

  1. That seems very wasteful 看来很浪费
  2. Far more importantly, it loses the entire structure. 更重要的是,它失去了整个结构。

For example purposes: 出于示例目的:

public void Example(object a,object b, object c)
{
    object[] ex = {a,b,c};
    object d = new MyCustomType();
}

Without using any indexers, how can I make ex hold {a,d,c} ? 如果不使用任何索引,我怎样才能使ex保持{a,d,c} Assume that the only way that I can access ex is through an enumerator. 假设我可以访问ex的唯一方法是通过枚举器。 There are no Add or AddAt methods in the type (played here by object[] . Assume that the underlying structure is unknown/highly complex. 该类型中没有AddAddAt方法(由object[]在此处播放。假设基础结构是未知的/高度复杂。

How can I do this? 我怎样才能做到这一点?

As payo said, your statement conflict with each other. 正如payo所说,您的陈述相互冲突。 You cannot iterate through an IEnumerable yet you are in a foreach loop, which is iteration. 您无法通过IEnumerable进行迭代,但是您处于foreach循环(即迭代)中。 And IEnumerable pretty much says you can enumerate through the collection. IEnumerable几乎说您可以通过集合进行枚举。 But here is my input on your question: 但是,这是我对您的问题的投入:

When enumerating through a collection you are limited on any attempt to change the data you are enumerating through. 枚举集合时,您尝试更改枚举通过的数据时会受到限制。 And you definitely cannot delete anything. 而且您绝对不能删除任何内容。 In part this is due to the potential of changing the enumeration. 部分原因是由于更改枚举的可能性。

A possible approach is to create a list of items, enumerate through the list and put what you want into the list. 一种可能的方法是创建项目列表,在列表中进行枚举,然后将所需内容放入列表中。 Then reload the IEnumerable assuming they expose .Add(IEnumerable list). 然后假设它们公开了.Add(IEnumerable list),然后重新加载IEnumerable。

In one situation I had items I wanted to delete from an IEnumerable, so I did a foreach, tracked each object I wanted to remove, then after the enumeration I did a Remove of each object that I had saved. 在一种情况下,我有一些要从IEnumerable中删除的项目,因此我进行了一次foreach,跟踪了要删除的每个对象,然后在枚举之后,对保存的每个对象进行了删除。

Nowadays, with linq, you can more easily do something like removing objects if you can phrase a well define query of what you want (leaving out what you do not want) then process against the IQueriable result set. 如今,使用linq,您可以更轻松地执行一些操作,例如删除对象,如果您可以对所需的内容进行明确定义的查询(保留不想要的内容),然后对IQueriable结果集进行处理。

In a word: linked lists . 一句话: 链表

You haven't said whether you need to implement IEnumerable (such as for use with LINQ), or how much control you have over the mysterious collection you refer to. 您没有说过是否需要实现IEnumerable (例如与LINQ一起使用),还是需要对引用的神秘集合进行多少控制。 But if your question is fundamentally, "how can I modify some kind of collection while iterating through it in C#?"...well, this is what linked lists are actually good (and extremely efficient) at. 但是,如果您的问题从根本上来说是“在C#中遍历它时如何修改某种集合?” ...那么,这就是链接列表实际上擅长(并且非常高效)的地方。 For example: 例如:

var intList = new LinkedList<int>(new []{ 1, 4, 5, 7, 12 });
var node = intList.First;
do {
    // do stuff with node
    if (node.Value < 3){
        node.List.AddAfter(node, node.Value + 1);
    } else if(node.Value == 7) {
        var prevNode = node.Previous;
        node.List.Remove(node);
        node = prevNode;
    }

    // Get the next node
    node = node.Next;
} while (node != null);

I'm not saying you should copy your source collecting into a linked list since we don't have enough information from you. 我并不是说您应该将您的来源收集复制到一个链表中,因为我们没有足够的信息。 But perhaps this can show you and future readers what linked lists are for -- namely, modifying while enumerating without an index accessor. 但这也许可以向您和未来的读者展示链接列表的作用-即在枚举时进行修改而无需索引访问器。

And note, if this collection you refer to is completely hypothetical, then there is no answer with the information you have provided: IEnumerable does not require any methods for modifying the "underlying collection." 请注意,如果您引用的集合完全是假设的,那么您所提供的信息将没有答案: IEnumerable不需要任何方法来修改“基础集合”。 In fact, IEnumerable does not require there to even be an underlying collection. 实际上, IEnumerable甚至不需要底层集合。 For example, here's a method that returns an IEnumerable<int> with no underlying collection: 例如,这是一个返回IEnumerable<int>且没有基础集合的方法:

public static IEnumerable<int> Range(int minValue, int maxValue) {
    int current = minValue;
    while (current <= maxValue) {
        yield return current;
        current++;
    }
}

The way you describe it, theres no way I can think of to replace the items easily. 按照您的描述方式,我无法想到轻松替换这些项目。
You claim that: 您声称:

  • There are no add/remove methods - no simple way to change 没有添加/删除方法-没有简单的更改方法
  • The underlying collection's format is unkown - makes the reflection option harder to use 基础集合的格式是未知的-使反射选项更难使用
  • You have only the enumerator exposed to you - meaning you can only foreach 您只有暴露给您的枚举数-这意味着您只能进行

The possible solutions are: 可能的解决方案是:

  • reflect the underlying type, to learn its format and to change anything you want by means of reflection 反映基础类型,了解其格式并通过反思来更改所需的任何内容
  • If possible, use deep copy,as ive already suggested. 如果可能的话,请使用深度复制(如已建议)。 Deep copy, if you are not familiar with the term, means you will update the object you want to replace and its properties in a recursion, as deep as needed, with the parallel values from the object you want to put instead of the replaced one. 深层复制,如果您不熟悉该术语,则意味着您将根据需要使用您要放置的对象的并行值(而不是被替换的对象)的并行值,根据需要进行深度递归更新要替换的对象及其属性。 。 This solution wont work, of course, if you care for the reference and not for the data/values of each object. 当然,如果您只关心引用而不是每个对象的数据/值,则此解决方案将行不通。 There are dozens of threads which explain how to use deep copy on SO, so it shouldnt be problematic to find a sample 有数十个线程解释了如何在SO上使用深度复制,因此找到示例应该没有问题

What methods of mutation does the original collection have? 原始收藏有哪些突变方法? If it supports the removal or replacement of items, by what means does it identify items to be removed or replaced? 如果它支持物品的删除或替换,它通过什么方式识别要删除或替换的物品?

Some classes which implement IEnumerable or IEnumerable<T> will allow enumeration to work sensibly even when the underlying collection is modified (items which are in the collection throughout the enumeration will be returned exactly ones, those which are in the collection for part of the enumeration will be returned at most once, and those which are not the collection at all during enumeration will not be returned at all). 某些实现IEnumerableIEnumerable<T>将允许枚举合理地工作,即使基础集合被修改(整个枚举中集合中的项目也将被精确返回,而那些在枚举中的集合中的项目将被完全返回)。将最多返回一次,而在枚举期间根本不是集合的那些将根本不会返回)。 If the class you're using behaves that way, great. 如果您使用的类的行为是这样,那就太好了。

Otherwise, your best bet is probably to build a list of "edits" while you're enumerating the class, and then apply those edits after enumeration is complete. 否则,您最好的选择可能是在枚举该类时构建“编辑”列表,然后在枚举完成后应用这些编辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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