【问题标题】:Remove element from a static List<MyClass>从静态 List<MyClass> 中删除元素
【发布时间】:2017-05-02 11:51:23
【问题描述】:

我对@9​​87654321@ 的方法有一些疑问。我有一个类(描述如下),用作列表的类型。
我的课是:

public class MyClass
{
   public string ID { get; set; }
   public myEnum CallType { get; set; }
   public object ObjToStore { get; set; }
}

我的List&lt;T&gt; 是这样实例化的:

private static List<MyClass> ListOfStoreObjects = new List<MyClass>();

我的麻烦是我将这些东西存储到这些列表中,我无法删除它们。我使用这些列表将临时数据存储在 Web 服务中(我想“走这条路”,所以请不要告诉我其他解决方案,谢谢)当然,一旦使用这些数据,我必须设法删除他们来自这个“缓冲区”。那么,有没有办法从静态列表中移除一个元素呢?

编辑

我使用的add函数是:

public bool AddToQueue(string id, myEnum callType, object objToAdd)
{
   try
   {
      MyClass elementToAdd = new MyClass();
      elementToAdd.ID = id;
      elementToAdd.CallType = callType;
      elementToAdd.ObjToStore = objToAdd;
      ListOfStoreObjects.Add(elementToAdd);

      return true;
   }
   catch
   {
      return false;
   }
}

我用来检索我需要的对象然后从列表中删除它的函数:

 public object RetrieveObj(string id, myEnum callType)
 {
     object obj = null;

     foreach(var element in ListOfStoreObjects)
     {
         if( element.ID == id && element.CallType == callType)
         {
             obj = element.ObjToStore;
             break;
         }
     }

     MyClass itemToRemove = new MyClass();
     itemToRemove.ID = id;
     itemToRemove.CallType = callType;
     itemToRemove.ObjToStore = obj;

     ListOfStoreObjects.Remove(itemToRemove);

     return obj;
 }

【问题讨论】:

  • 为什么Remove 有问题?什么没有按预期工作?
  • 有什么问题,线程相关还是其他什么?
  • @MightyBadaboom 问题是,实际上当我在列表中调用 List.Remove(T) 时,它不起作用,它不会删除任何东西。
  • @ΦXocę 웃 Пepeúpa ツ 你什么意思?我无法理解你的问题...
  • 实际上,您正在删除列表中不存在的新项目,因此您需要在此处添加 hack,请参阅@Karolis 对此的回答。尝试itemToRemove == sameIdItemfromListitemToRemove.Equal(sameIdItemfromList) 以进一步了解IEqualityComparer

标签: c# list static


【解决方案1】:

您需要实现IEquatable&lt;T&gt;,它被泛型List&lt;T&gt; 集合内部使用以确定自定义类型的相等性。

这是一个示例(假设 ID 是您的唯一标识符):

public class MyClass : IEquatable<MyClass>
{
    public string ID { get; set; }
    public myEnum CallType { get; set; }
    public object ObjToStore { get; set; }

    public bool Equals(MyClass x)
    {
        return x.ID.Equals(this.ID);
    }
}

More about the interface.

编辑

您创建了一个与您尝试删除的对象不共享引用相等的新对象。上面提供的方法可以解决问题,但它不是最适合您的情况的解决方案。

我建议通过index 删除,前提是您非常喜欢使用List 而不是HashSet

 for(int i = 0; i < ListOfStoreObjects.Count; i++)
 {
     if( ListOfStoreObjects[i].ID == id && ListOfStoreObjects[i].CallType == callType)
     {
         ListOfStoreObjects.RemoveAt(i);
         break;
     }
 }

为什么是RemoveAt 而不是RemoveArray 作为List 的底层集合,O(1) 按索引查找元素,因此对于这种类型的集合,由于数组在内存中解析方式的语义,它是删除项目的最有效方法。 此外,如果您查看 .NET 源代码,Remove 方法将再次循环通过 collection 并删除调用 Equals 方法的元素以检查相等性。

【讨论】:

  • 我会尽快尝试,但现在我建议您查看我对问题的编辑。我添加了我使用的 Add 方法以及 .Remove(T) 失败的方法。无论如何,现在谢谢你,我会告诉你它是否有效。
  • 单独定义IEqualityComparer&lt;T&gt; won't make List&lt;T&gt;.Remove() 按预期工作。应该为此实施IEquatable&lt;T&gt;
  • @DmitryEgorov 哦,天哪……真丢脸。我知道 HashCode 不应该在那里。它用于分桶集合而不是基于索引。感谢您指出这一点!已更正。
【解决方案2】:

您正在错误地移除对象。您必须像这样删除它:

public MyClass RetrieveObj(string id, myEnum callType)
{
     MyClass obj = null;

     foreach(var element in ListOfStoreObjects)
     {
         if( element.ID == id && element.CallType == callType)
         {
             obj = element;
             break;
         }
     }
     ListOfStoreObjects.Remove(obj);

     return obj;
}

这是一个非常常见的错误。您正在找到正确的对象,而不是使用该实例,而是创建了该类的新对象,该对象从不与列表中的任何对象匹配。

替代解决方案

分享一种更简单的单行方式来做你想做的事情:

ListOfStoreObjects.RemoveAll(x => x.ID == id && x.CallType == callType);

【讨论】:

  • 它给了我一个 sintax 错误,因为我无法将 object 转换为 MyClass
  • 将函数定义的返回类型更新为MyClass。我已经用同样的变化更新了答案。
  • 好的,它看起来工作得很好。我用的是单线的方式,实现起来更简单快捷哈哈。无论如何,如果我只想删除表达式的第一个结果,我必须使用您编写的其他代码,对吗?
  • 好的,我可以确认这两种方式都可以正常工作。所以我会将此标记为我的问题的解决方案,但其他问题也很有趣
【解决方案3】:

理想情况下,Remove() 应该可以工作,并且是更好且正确的方法。您应该尝试找出您没有正确使用它的原因。但如果你仍然不能,你可以尝试这样的事情。您应该将st.IsCompleted 替换为另一个条件,以表明该项目 将被删除。请注意,这不如Remove() 高效,仅作为一种解决方法。

ListOfStoreObjects = ListOfStoreObjects.Where(st => st.IsCompleted).ToList();

【讨论】:

  • 如果我不提出其他解决方案,我将使用此解决方法。
【解决方案4】:

由于您在调用 List&lt;T&gt;.Remove() 时创建了一个新的 MyClass 实例,因此您必须实现 IEquatable&lt;T&gt; 来告诉 Remove 在查找要删除的集合项

MyClass中实现IEquatable&lt;T&gt;接口:

public class MyClass : IEquatable<MyClass>
{
    public string ID { get; set; }
    public myEnum CallType { get; set; }
    public object ObjToStore { get; set; }

    public bool Equals(MyClass other)
    {
        return other != null && other.ID == this.ID;
    }
}

来自List<T>.Remove documentation

如果类型 T 实现了 IEquatable 泛型接口,则等式 comparer 是该接口的 Equals 方法;否则, 默认相等比较器是 Object.Equals。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    相关资源
    最近更新 更多