替换对象列表中的对象

问题描述 投票:0回答:6

在 C# 中,如果我有一个

List<T>
,并且有一个
T
类型的对象,如何将
List<T>
中的特定项目替换为
T
类型的对象?

这是我尝试过的:

List<CustomListItem> customListItems = new List<CustomListItem>();
CustomListItem customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue};
CustomListItem customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
CustomListItem customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

customListItems.Add(customListItem1);
customListItems.Add(customListItem2);
customListItems.Add(customListItem3);

CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
customListItem2 = newCustomListItem;

在上面的代码中,我想用

customListItem2
替换
newCustomListItem

我是否必须删除列表中的项目,然后插入新项目?我可以不做简单的

customListItem2 = newCustomListItem
作业吗?

用另一个项目替换列表中的项目的最有效方法是什么?

c# .net list variable-assignment generic-list
6个回答
94
投票

你必须更换的是物品,而不是

customListItem2
的值。只需替换以下内容:

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
customListItem2 = newCustomListItem;

有了这个:

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();
var index = customListItems.IndexOf(customListItem2);

if(index != -1)
    customListItems[index] = newCustomListItem;

编辑:

正如 Roman R. 在评论中所述,您可以用简单的

.Where(predicate).First()
替换
First(predicate)

customListItem2 = customListItems.First(i=> i.name == "Item 2");

12
投票
var customListItems = new List<CustomListItem>();
var customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue };
var customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
var customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

customListItems.Add(customListItem1);
customListItems.Add(customListItem2);
customListItems.Add(customListItem3);

var newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItems[customListItems.FindIndex(x => x.name == "Item 2")] = newCustomListItem;

public static class ListExtensions
{
    public static void Replace<T>(this List<T> list, Predicate<T> oldItemSelector , T newItem)
    {
        //check for different situations here and throw exception
        //if list contains multiple items that match the predicate
        //or check for nullability of list and etc ...
        var oldItemIndex = list.FindIndex(oldItemSelector);
        list[oldItemIndex] = newItem;
    }
}

然后

customListItems.Replace(x => x.name == "Item 2", newCustomListItem);

2
投票

如果列表的顺序对你来说不重要 你可以试试这个

CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

customListItem2 = customListItems.Where(i=> i.name == "Item 2").First();  

customListItems.Remove(customListItem2);
customListItems.Add(newCustomListItem );

2
投票

您可以使用选择来构建一个新的 iEnumerable 并替换项目:

customListItems.Select(x => x.name == "Item 2" ? newItem : x).ToList();

我没有测试性能,但我发现这个解决方案非常简洁和明确。


0
投票

我通常有一些定义关键字段的基本接口,以便我可以更轻松地使用泛型。因此继承 IKey 的类将有一个字符串 Key 字段,它是记录的唯一标识符。

因此,在哈米德的示例之上构建,但具有“添加或替换”概念:

    public static void AddOrReplace<T>(this List<T> items, T newItem) where T : class, IKey
    {
        items.AddOrReplace(x => x.Key == newItem.Key, newItem);
    }

    public static void AddOrReplace<T>(this List<T> items, Predicate<T> oldItemSelector, T newItem)
    {            
        var index = items.FindIndex(oldItemSelector);
        if (index < 0)
        {
            items.Add(newItem);
        }
        else
        {
            items[index] = newItem;
        }            
    }

然后为了实现这些扩展,我可以使用与 list.Add() 类似的语法:

list.AddOrReplace(newItem);

-1
投票

另一种方法是使用

DynamicData
包,列表中还有很多其他设施:

快速解答

确保已安装该软件包:

Install-Package DynamicData -Version 7.4.3

然后

using DynamicData;

DynamicData.ListEx.Replace<CustomListItem>(customListItems, customListItem2, newCustomListItem);

以下是完整的工作解决方案。

工作示例

我的自定义项目类别

public class CustomListItem
{
    public string name; 
    public DateTime date;

    public override string ToString()
    {
        return name + ", " + date.ToString();
    }
}

在主要尝试中,请确保在替换之前注释掉分配。

static void Main(string[] args)
{
    List<CustomListItem> customListItems = new List<CustomListItem>();
    CustomListItem customListItem1 = new CustomListItem() { name = "Item 1", date = DateTime.MinValue };
    CustomListItem customListItem2 = new CustomListItem() { name = "Item 2", date = DateTime.MinValue };
    CustomListItem customListItem3 = new CustomListItem() { name = "Item 3", date = DateTime.MinValue };

    customListItems.Add(customListItem1);
    customListItems.Add(customListItem2);
    customListItems.Add(customListItem3);

    CustomListItem newCustomListItem = new CustomListItem() { name = "Item 4", date = DateTime.Now };

    customListItem2 = customListItems.Where(i => i.name == "Item 2").First();
    //customListItem2 = newCustomListItem;


    DynamicData.ListEx.Replace<CustomListItem>(customListItems, customListItem2, newCustomListItem);

    foreach(var customListItem in customListItems)
    {
        Debug.Print("\n" + customListItem.ToString());
    }
}

references: https://github.com/reactivemarbles/DynamicData.
https://dynamic-data.org
© www.soinside.com 2019 - 2024. All rights reserved.