How to make the following code shorter, perhaps using anonymous method or extensions and LINQ.

Since I have to repeat this code several times and I want to make it as succinct as possible.

var imagesToUnlock = App.ImageListVM.Items.Where(img => img.Category == key);

foreach (var image in imagesToUnlock)
{
    image.IsLocked = false;
}
有帮助吗?

解决方案

The other solutions here feel dirty because they mutate objects in a collection via the use of LINQ.

I would instead, put the code and the filter condition into an extension method and call that:

public static IEnumerable<Item> UnlockWhere(this IEnumerable<Item> list, Func<Item, bool> condition) {
    foreach (var image in list)
        if (condition(image)) {
            image.IsLocked = false;
            yield return image;
        }
}

The keeps the immutability-concerns of LINQ intact and still produces the expected result.

The call becomes:

var unlockedItems = App.ImageListVM.Items.UnlockWhere(img => img.Category == key);

EDIT

Re-written to completely remove LINQ. Instead, this new method iterates only once and returns a new, mutated collection.

其他提示

Not the most efficient way to do it, but I believe you can do

var imagesToUnlock = App.ImageListVM.Items.Where(img => img.Category == key).ToList().Foreach(f => f.IsLocked = false);

Check out the Foreach method on List<T> for more info.

I would also like to note (as some have pointed out in the comments) that this is not considered best practice by some people. You should take a look at this article by Eric Lippert, who explains the issue in better detail.

Here's a stab as an extension method

Code

         public static IEnumerable<T> SetPropertyValues<T>(this IEnumerable<T> items, Action<T> action)
        {
            foreach (var item in items)
            {
                action(item);
                yield return item;
            }
        }

Usage

        private class Foo
        {
            public string Bar { get; set; } 
        }

        [TestMethod]
        public void SetPropertyValuesForMiscTests()
        {
            var foos = new[] { new Foo { Bar = "hi" }, new Foo { Bar = "hello" } };
            var newList = foos.SetPropertyValues(f => f.Bar = "bye");

            Assert.AreEqual("bye", newList.ElementAt(0).Bar);
            Assert.AreEqual("bye", newList.ElementAt(1).Bar);
        }

I tested it and it works fine.

Yeah you can do this. Adapted from this answer.

imagesToUnlock.Select(i => {i.IsLocked = false; return i;}).ToList();

Edit: A lot of people are saying this is bad practice. I agree with dasblinkenlight here.. Exploring the limits of LINQ and C# is our duty as programmers. It isn't unreasonable to change the objects type from the DTO to the view model or domain object, I know its not the best, but if encapsulated and commented it isn't the end of the world to use select to do this. But please be conscious of the best practices explained by Eric.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top