简体   繁体   English

在foreach循环中重新分配object c#

[英]Reassign object in foreach loop c#

Not sure I understand why I can do this with a for loop and not a foreach loop?不确定我是否理解为什么我可以使用 for 循环而不是 foreach 循环来做到这一点?

This is the code that works.这是有效的代码。 Looping through a BindingList Products, finding a match and then assigning that product at index i to the new product that's passed in.循环遍历 BindingList Products,找到匹配项,然后将索引 i 处的产品分配给传入的新产品。

 public static void UpdateProduct(int productToUpdateID, Product productToUpdate)
        {
            

            for (int i = 0; i < Products.Count; i++)
            {
                if (Products[i].ProductID == productToUpdateID)
                {
                    Products[i] = productToUpdate;
                }
            }
        }
            

If I try to do this with a foreach loop I get an error that I cannot assign to the iterator variable.如果我尝试使用 foreach 循环执行此操作,则会收到无法分配给迭代器变量的错误。 What is the reasoning for this and is there a way to get around it or is using a for loop for this kind of problem the best solution?这样做的原因是什么,有没有办法解决这个问题,或者使用 for 循环来解决这类问题是最好的解决方案?

This is essentially what I'm trying to do.这基本上就是我想要做的。

          public static void UpdateProduct(int productToUpdateID, Product productToUpdate)
        {

            foreach(Product product in Products)
            {
                if (product.ProductID == productToUpdateID)
                {
                    product = productToUpdate;
                }
            }
        }
            

I can do something like this and reassign all the properties explicitly but want to see if there is another way to do it.我可以做这样的事情并明确地重新分配所有属性,但想看看是否有另一种方法可以做到这一点。

            foreach(Product product in Products)
            {
                if (product.ProductID == productToUpdateID)
                {
                    product.Name = productToUpdate.Name;
                    
                }
            }

Thanks!谢谢!

The foreach construct is for when you want to do something with each item in the list. foreach结构用于当您想要对列表中的每个项目执行某些操作时。 That does not seem to be what you are doing.那似乎不是你在做什么。 You are modifying the list itself, by removing an item and replacing it.您正在修改列表本身,通过删除一个项目并替换它。

Personally I would not use a loop at all, I'd just remove the old item and add the new one.就我个人而言,我根本不会使用循环,我只是删除旧项目并添加新项目。

public static void UpdateProduct(int productToUpdateID, Product productToUpdate)
{
    Products.RemoveAll( x => x.ProductID == productToUpdateID );
    Products.Add( productToUpdate );
}

Or if you wish to preserve order:或者如果你想保持顺序:

public static void UpdateProduct(int productToUpdateID, Product productToUpdate)
{
    var index = Products.FindIndex( x => x.ProductID == productToUpdateID );
    Products[index] = productToUpdate;
}

The foreach loop iterates over the elements of a collection, and the iteration variable is simply a reference to the current element in the collection. foreach循环遍历集合的元素,迭代变量只是对集合中当前元素的引用。

The reason you cannot modify the iteration variable itself is that it is a read-only reference to the element in the collection.您不能修改迭代变量本身的原因是它是对集合中元素的只读引用。 Modifying the iteration variable would not change the element in the collection;修改迭代变量不会改变集合中的元素; it would only change the reference.它只会改变参考。

Alternative ways are already mentioned in the above answers.上述答案中已经提到了替代方法。

Just for the record.只是为了记录。 The best way is to use for loop (not linq, and not foreach).最好的方法是使用 for 循环(不是 linq,也不是 foreach)。 But if you want to use linq you can do it in one line)但是如果你想使用 linq 你可以在一行中完成)

products = products.Select(x => x = x.ProductID == productToUpdate.ProductID?productToUpdate:x).ToList();

The reasons have already been given, but as a minor detail: this is sometimes possible;原因已经给出,但作为一个次要的细节:这有时可能的; there is an alternative syntax in recent C# that uses a ref -local for the iterator value:最近的 C# 中有一种替代语法,它使用ref -local 作为迭代器值:

foreach (ref [readonly] SomeType value in source)

which is only available for some scenarios - naked arrays, spans, or custom iterator types with a ref -return Current - and as long as the optional readonly modifier is not used, you can assign directly via the value variable, since this is a direct reference to the underlying source.这仅适用于某些场景 - 裸 arrays,跨度或带有ref -return Current的自定义迭代器类型 - 只要不使用可选的readonly修饰符,就可以直接通过value变量分配,因为这是一个直接对底层资源的引用。 The uses for this are rare and niche.这方面的用途很少见且利基。 If Products is a List<T> , you could combine this with CollectionMarshal.AsSpan(...) to achieve what you want, but frankly I'd consider that hacky (apart from other things, it would bypass the list's internal change protections).如果ProductsList<T> ,您可以将它与CollectionMarshal.AsSpan(...)结合起来以实现您想要的,但坦率地说,我认为这很老套(除其他外,它会绕过列表的内部更改保护). Basically: don't do this, but: it isn't entirely impossible.基本上:不要这样做,但是:这并非完全不可能。

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

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