13

Hello how can i remove item from generic list here is my code im trying to do it right but i dont know where i make mistake;/

Users us_end = new Users();
foreach (var VARIABLE in ((List<Users>)Application["Users_On"]))
{
    if(VARIABLE.Id == (int)Session["Current_Id"])
    {
        us_end.Name = VARIABLE.Name;
        us_end.Id = VARIABLE.Id;
        us_end.Data = VARIABLE.Data;
    }
}
List<Users> us = ((List<Users>)Application["Users_On"]);
us.Remove(us_end);
Application["Users_On"] = us;
vivid
  • 1,115
  • 2
  • 14
  • 34
  • 1
    Well, what doesn't behave as expected? (For `Remove` to work the item needs to correctly implement `Equals`). –  Jun 10 '12 at 18:22
  • this doesnt really make alot of sense: you are overwriting every Users object you make inside that foreach.. – Thousand Jun 10 '12 at 18:23
  • Also, you cast `Application["Users_On"]` to a `List – Ed S. Jun 10 '12 at 18:24

6 Answers6

19

You have to get the same object to remove, not a copy.

Users us_end;

foreach (var VARIABLE in ((List<Users>)Application["Users_On"]))
{
    if(VARIABLE.Id == (int)Session["Current_Id"])
    {
       us_end = (Users)VARIABLE;
       break;
    }
}

if (us_end != null)
{
    List<Users> us = ((List<Users>)Application["Users_On"]);
    us.Remove(us_end);
    Application["Users_On"] = us;
}

Edit:

Just to clarify an address here, as pst pointed, you could also implement the IEquatable interface and some overridings like on the Groo's answer to make it work, but i think it's overkill on this specific subject. Giving this as the most common practice, but making clear that it's also possible to remove items from a list, even if they are diferent instances or even diferent objects with a technique like that.

Ref.: http://msdn.microsoft.com/en-us/library/ms131187.aspx

Ricardo Souza
  • 16,030
  • 6
  • 37
  • 69
  • So why haven't you posted the correct answer? if you think you are on a mood for explaining the overriding of a comparison just to remove an object from a list, do it so. I understand your pont of view, but please, make your own answer and explain it so he can mark it as the correct one instead of falling on me. – Ricardo Souza Jun 10 '12 at 19:09
  • Because the answers are "correct", including this one, just [initially] misleading :) Nit: It doesn't need to implement `IEquatable` as object.Equals(object) -- remember this is polymorphic! -- can still be used. I use `Remove` and other Equals-*requiring* methods and just "expect it to work" under the equality I have defined for my types. That is, I would expect `a.Equals(b)` to work in in the same manner as `l.Add(a); l.Remove(b)` works, and vice-versa. –  Jun 10 '12 at 21:53
10

By default, object equality is compared by reference in .NET (unless Equals is overriden, every object inherits from object.Equals). If you want the Remove method to find your object, you cannot pass a new object.

The simplest way would be to find the actual object which has desired properties, and then remove it:

var id = (int)Session["Current_Id"];
var list = (List<Users>)Application["Users_On"];  

// find the exact item to remove.
var itemToRemove = list.FirstOrDefault(u => u.Id = id);

// if found, remove it
if (itemToRemove != null)
{
    list.Remove(itemToRemove);
}
vgru
  • 49,838
  • 16
  • 120
  • 201
  • But `Equals` is virtual. This does not make sense to me. –  Jun 10 '12 at 18:24
  • @pst: a virtual method, unless explicity overriden, behaves like defined in the base class. `Object.Equals` compares by reference. – vgru Jun 10 '12 at 18:33
  • I can accept this after the update (it was wrong before, as the definition of Users is not known). –  Jun 10 '12 at 18:33
6

You are creating a new Users object - this is not the same as any object already in Application["Users_On"] (it will have a different reference), so it will not be removed.

This assumes that Equals and/or IEquatable<T> were not overridden/implemented in Users.

List<Users> us = ((List<Users>)Application["Users_On"]);
Users us_end = us.Where(u => u.Id == (int)Session["Current_Id"]).FirstOrDefault();
us.Remove(us_end);
Application["Users_On"] = us;

By the way - your variable naming is not very good - go for more descriptive names.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 1
    Yes, it works on equality and by default for Objects, equality is implemented by checking reference ... – Nitin Midha Jun 10 '12 at 18:24
  • @pst - Which for reference type will be reference equality. – Oded Jun 10 '12 at 18:24
  • @Oded `class Users { override Equals }` ?? –  Jun 10 '12 at 18:25
  • -1 Because this fails to address "This method determines equality using the default equality comparer EqualityComparer.Default for T, the type of values in the list." http://msdn.microsoft.com/en-us/library/cd666k3e.aspx and "The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T." http://msdn.microsoft.com/en-us/library/ms224763.aspx –  Jun 10 '12 at 18:32
  • That is, "it will have a different reference" does not imply `Remove` will not work. –  Jun 10 '12 at 18:35
  • @pst: a downvote usually indicates that an "answer is not useful". This is indeed the general and shortest solution to removing an item according to a specific property. You cannot always override `Equals` nor implement `IEquatable`, and even if you did, removing would always require creating the entire object (populating all properties like OP did), which is not practical. – vgru Jun 10 '12 at 18:39
  • @Groo I explained the downvote. It is misleading (and I only expect/demand the best from Oded by now :-). The implementation of `Users` is not known. I while I suspect the conclusion is correct (as with your answer), this answers fails to address `Equals` (which your answer covered in a later update). –  Jun 10 '12 at 18:42
  • @pst - Fair enough, though I think the assumptions that `Equals` was not overridden and that `IEquatable` was not implemented are fair (nevertheless, updated answer with said assumptions). – Oded Jun 10 '12 at 18:59
0

What's about:

List<Users> us = ((List<Users>)Application["Users_On"]);
Users us_end = us.First(x => x.ID == (int)Session["Current_Id"]);
us.Remove(us_end);
Application["Users_On"] = us;
Omar
  • 16,329
  • 10
  • 48
  • 66
0

Remove it in place by finding the item inside the remove statement, not via an additional copy:

List<Users> us = ((List<Users>)Application["Users_On"]);
us.Remove(us.FirstOrDefault(u => u.ID == (int)Session["Current_Id"]));
Application["Users_On"] = us;
Robert
  • 103
  • 7
0

As someone said in the previous answers: object equality is compared by reference in .NET. But you can benefit from the difference between classes and structs by simply turning your element T inside List from class to struct.

Jakub
  • 125
  • 1
  • 3
  • 9