List<Type> Remove - c#

Somebody explain to me this:
I am trying to delete items from a list with matching ids contained in another list of strings.
Step 1 is as below:
I'm trying to delete Items from myListingSyncIDs where the ListingNumber matches ListingNumbers in lstListingsUpdatedIn24Hrs.
The item at [0] Equals a value from lstListingsUpdatedIn24Hrs, as shown in Step 2:
But as shown in Step3: The Remove fails:
Then After doing a RemoveAll(func) Step4: The Remove works
Somebody explain why the Remove(item) doesn't work, Please ...
Code:
myListingSyncIDs.AddRange(myListingSync.Listings);
#region Remove Listing References Fetched In The Last 24Hrs
// Listing References Fetched In The Last 24Hrs
// These will be excluded to optimise the running of the App.
// Basically meaning that a complete sync of all listings
// will only be done once every 24hrs
// So that if this is run every hr, it will not slow down the most recent additions
List<String> lstListingsUpdatedIn24Hrs = DAL.PropertyPortalDAL.GetSahtWebserviceUpdatesIn24Hrs();
List<P24SyncService.ListingSyncItem> myListingsUpdatedIn24Hrs =
lstListingsUpdatedIn24Hrs.Select(p => new P24SyncService.ListingSyncItem()
{
ListingNumber = p,
Status = P24SyncService.ListingState.AddedModified
}).ToList();
foreach (P24SyncService.ListingSyncItem myLSI in myListingsUpdatedIn24Hrs)
{
myListingSyncIDs.Remove(myLSI);
}
myListingSyncIDs.RemoveAll(p => lstListingsUpdatedIn24Hrs.Contains(p.ListingNumber));
#endregion
ListingSyncItem is:
public partial class ListingSyncItem {
private string listingNumberField;
private ListingState statusField;
/// <remarks/>
public string ListingNumber {
get {
return this.listingNumberField;
}
set {
this.listingNumberField = value;
}
}
/// <remarks/>
public ListingState Status {
get {
return this.statusField;
}
set {
this.statusField = value;
}
}
}

At a guess, your ListingSyncItem type doesn't override Equals, so List<T>.Remove doesn't know that the item to remove is "equal" to the item in your list.
Simply overriding Equals and GetHashCode appropriately (to check for the equality of ListNumber and Status, presumably, and build a hash code based on those) should fix the problem.
For RemoveAll, you're providing a predicate. That doesn't use ListingSyncItem.Equals, which is why it's working.

I can't be sure without seeing the definition of ListingSyncItem, but I'm guessing this has to do with the fact that you have two instances referring to the same item.
You know that two different instances with the same ListingNumber refer to the same conceptual object, but the List<> doesn't. By default, .NET knows two objects are identical if they share the same instance, but since you're creating a new ListingSyncItem in your internal lambda function, it's not being removed.
What you should do is implement IEquatable in your ListingSyncItem class and make it return True for two objects with the same ListingNumber. Then List will know to remove the right items from the list.

As stated, it is because you arent overriding the Equals.
By default, it will check for ref equality. Which, obviously, isnt the case here.
Either override Equals and GetHashCode or use some way of getting the correct reference (lambdas for instance)

Related

How to remove duplicates of the same code with different roles

Change the text of the object's children and reassign them.
I want to know the best way to clean up duplicate code.
The former stores the value, and the latter gets the value.
public void OnClickKeypad()
{
RotateNumber();
}
public void RotateNumber()
{
transform.GetChild(0).GetComponent<UnityEngine.UI.Text>().text = ((int.Parse(transform.GetChild(0).GetComponent<UnityEngine.UI.Text>().text)+1) % 10).ToString();
// "transform.GetChild(0).GetComponent<UnityEngine.UI.Text>().text" is a duplicate.
}
If your problem is that you have to type transform.GetChild(0).GetComponent<UnityEngine.UI.Text>().text all over the place, then hide it behind a method or property getter with a useful name:
private UnityEngine.UI.Text firstTextChild => transform.GetChild(0).GetComponent<UnityEngine.UI.Text>();
Now you can use that from within that class:
firstTextChild.text = firstTextChild.text + "1";

xUnit Equal two same collections, same order, same types, returns false

Shouldn't xUnit Equal method return true if two collections are equal meaning have same objects in the same order?
Example:
var result = new List<item>()
{
new item()
{
TypeId = typesEnum.Integer,
Code = "code"
},
new item()
{
TypeId = typesEnum.Integer,
Code = "code2"
}
}
and Assert.Equal(expectedResult, result) returns false.
and I have exactly the same list in expectedResult, checked one by one, every property, type, everything. When I write my own IEqualityComparer and compare every single property of item class in it then the result is true. But default comparer returns false. Is that how it's supposed to work for xUnit? If so the question is how to compare if two collections are equal like equivalent?
Custom comparer looks like this:
internal class ItemComparer : IEqualityComparer<Item>
{
public bool Equals(Item x, Item y)
{
return x.Code.Equals(y.Code) && x.TypeId.Equals(y.TypeId)
}
public int GetHashCode(Item obj)
{
return obj.GetHashCode();
}
}
Here's a link to similiar question:
CLICK
And the answer is that it should work like I think it should without having to write my own comparer. The question is why doesn't it?
I use xUnit 2.4.1
It is not an XUnit issue or particularity, but how C# works. When you have two objects non-primitive, with the same values inside, they are equivalent but not equals - internally they have different memory references for each property. You can even try to compare both using == or .Equals() inside an if statement, and it will return false.
This answer explains very well about this subject
What you could do:
Overwrite comparison operators and use Assert.True(), and compare them in order to return a true;
Use a library that provides a comparison by equivalency, like FluentAssertion: object1.Should().BeEquivalentTo(object2);

Object reference updating, update all collections property?

Introduction
I found a very weird situation, so essentially I've a collection property called Matches and an object property called Match.
The Matches collections contains a list of item of Match, like this:
private ObservableCollection<Match> _matches = new ObservableCollection<Match>();
public ObservableCollection<Match> Matches
{
get { return _matches; }
}
this collection is valorized when the application start, infact, the software take some data from an Internet site and then, with a scraper fill the collection with the correspond object model Match.
Where the bug start
The Matches collection is binded to a DataGrid. When the user click on an element (Match), available on the DataGrid, the code fire the event SelectionChanged, inside this event I create a copy of the Match clicked, so I can use this object inside all my application:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
as you can see with the use of Linq, I check if the Match clicked by the user have the same link of a Match contained in the Matches collection, infact, each Match in the collection have a unique link like a GUID for example.
The bug
The Match object look like this:
private Match _match;
public Match Match
{
get { return _match; }
set
{
_match = value;
OnPropertyChanged();
}
}
and as I said it contains the Match clicked by the user. This object allow me to get the data from Internet only for this Match, from all methods inside my app. This working pretty well. Until now.
My application allow the user to apply some filters, essentially the user press a button and then the Match saved is updated with the property filled by the user, for example:
Match.League.Rounds = availableRounds;
this code cause the bug, but I'll try to explain the bug better later, I need to explain a bit what happen here.
Essentially the current Match saved in the application should update only the own property League.Rounds, this property is a list of Rounds available for this Match, the structure is very simple:
public class Round
{
public int Id { get; set; }
public string Name { get; set; }
}
the update working good but, the line Match.League.Rounds = availableRounds; update also all the property League.Rounds available in the objects collection Matches.
I don't understand why happen this, I've not created a reference of the object clicked:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Practice example of what's happening
before filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 10 and Name foo
after filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 11 and Name foofoo
but it should not be modified, only the Match should be modified.
but a new object. Someone could explain how to fix this? Best regards.
I've not created a reference of the object clicked
Yes, you have. This does not create a new Match object:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
It gets a reference to the already existing Match object in the Matches collection.
If you want to create a new object, you should use the new operator:
var existing = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Match match = new Match();
//set all properties of the new object...
match.Prop1 = existing.Prop1;
Also note that you need to create new Round objects as well. You should consider implementing the IClonable interface.
The FirstOrDefault() method doesn't clone the object for you.

Reflection, contravariance and polymorphism

I have a base class (abstract) with multiple implementations, and some of them contain collection properties of other implementations - like so:
class BigThing : BaseThing
{
/* other properties omitted for brevity */
List<SquareThing> Squares { get; set; }
List<LittleThing> SmallThings { get; set;}
/* etc. */
}
Now sometimes I get a BigThing and I need to map it to another BigThing, along with all of its collections of BaseThings. However, when this happens, I need to be able to tell if a BaseThing in a collection from the source BigThing is a new BaseThing, and thus should be Add()-ed to the destination BigThing's collection, or if it's an existing BaseThing that should be mapped to one of the BaseThings that already exist in the destination collection. Each implementation of BaseThing has a different set of matching criteria on which it should be evaluated for new-ness. I have the following generic extension method to evaluate this:
static void UpdateOrCreateThing<T>(this T candidate, ICollection<T> destinationEntities) where T : BaseThing
{
var thingToUpdate = destinationEntites.FirstOrDefault(candidate.ThingMatchingCriteria);
if (thingToUpdate == null) /* Create new thing and add to destinationEntities */
else /* Map thing */
}
Which works fine. However I think I am getting lost with the method that deals in BigThings. I want to make this method generic because there are a few different kinds of BigThings, and I don't want to have to write methods for each, and if I add collection properties I don't want to have to change my methods. I have written the following generic method that makes use of reflection, but it is not
void MapThing(T sourceThing, T destinationThing) where T : BaseThing
{
//Take care of first-level properties
Mapper.Map(sourceThing, destinationThing);
//Now find all properties which are collections
var collectionPropertyInfo = typeof(T).GetProperties().Where(p => typeof(ICollection).IsAssignableFrom(p.PropertyType));
//Get property values for source and destination
var sourceProperties = collectionPropertyInfo.Select(p => p.GetValue(sourceThing));
var destinationProperties = collectionPropertyInfo.Select(p => p.GetValue(destinationThing));
//Now loop through collection properties and call extension method on each item
for (int i = 0; i < collectionPropertyInfo.Count; i++)
{
//These casts make me suspicious, although they do work and the values are retained
var thisSourcePropertyCollection = sourceProperties[i] as ICollection;
var sourcePropertyCollectionAsThings = thisSourcePropertyCollection.Cast<BaseThing>();
//Repeat for destination properties
var thisDestinationPropertyCollection = destinationProperties[i] as ICollection;
var destinationPropertyCollectionAsThings = thisDestinationPropertyCollection.Cast<BaseThing>();
foreach (BaseThing thing in sourcePropertyCollectionAsThings)
{
thing.UpdateOrCreateThing(destinationPropertyCollectionAsThings);
}
}
}
This compiles and runs, and the extension method runs successfully (matching and mapping as expected), but the collection property values in destinationThing remain unchanged. I suspect I have lost the reference to the original destinationThing properties with all the casting and assigning to other variables and so on. Is my approach here fundamentally flawed? Am I missing a more obvious solution? Or is there some simple bug in my code that's leading to the incorrect behavior?
Without thinking too much, I'd say you have fallen to a inheritance abuse trap, and now trying to save yourself, you might want to consider how can you solve your problem while ditching the existing design which leads you to do such things at the first place. I know, this is painful, but it's an investment in future :-)
That said,
var destinationPropertyCollectionAsThings =
thisDestinationPropertyCollection.Cast<BaseThing>();
foreach (BaseThing thing in sourcePropertyCollectionAsThings)
{
thing.UpdateOrCreateThing(destinationPropertyCollectionAsThings);
}
You are losing your ICollection when you use Linq Cast operator that creates the new IEnumerable<BaseThing>. You can't use contravariance either, because ICollectiondoes not support it. If it would, you'd get away with as ICollection<BaseThing> which would be nice.
Instead, you have to build the generic method call dynamically, and invoke it. The simplest way is probably using dynamic keyword, and let the runtime figure out, as such:
thing.UpdateOrCreateThing((dynamic)thisDestinationPropertyCollection);

Remove one list from another mvc

I have two lists of the same type and I am trying to subtract the information in one list from the other and then save the result into the model.
I have tried two ways of doing it and so far I can't get either to work:
These are the two lists:
List<ApplicationsDetailsModel> AppList = ctx.Database.SqlQuery<ApplicationsDetailsModel>("exec get_applications_r").ToList();
var AppExceptionList = new List<ApplicationsDetailsModel>();
foreach(var g in AnIrrelevantList)
{
AppExceptionList.Add(new ApplicationsDetailsModel()
{
AppNum = g.AppNum,
AppName = g.AppName
});
}
So they now both have different data in the same format.
model.AppList = AppList.Except(AppExceptionList).ToList();
This doesn't bring up any errors but it also doesn't subtract the second list from the first.
var onlyInFirst = AppList.RemoveAll(a => AppExceptionList.Any(b => AppList == AppExceptionList));
I got this idea from this question.
Anyone know where I am going wrong?
The instances are not the same and are therefore not found to be equal by Except since it's checking for reference equal (which is obviously never going to be the case). For your situation you need to write a custom equality comparer... I've taken a stab at it here...
public class ApplicationsDetailsModelEqualityComparer : IEqualityComparer<ApplicationsDetailsModel>
{
public bool Equals(ApplicationsDetailsModel x, ApplicationsDetailsModel y)
{
return x.AppNum == y.AppNum && x.AppName == y.AppName;
}
public int GetHashCode(ApplicationsDetailsModel obj)
{
int hashCode = (obj.AppName != null ? obj.AppName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ obj.AppNum.GetHashCode();
return hashCode;
}
}
Usage...
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelEqualityComparer()).ToList();
Note that I'm assuming your AppNum and AppName together uniquely identify your objects in your list.
The Except method doesn't know how to compare two objects of type ApplicationsDetailsModel. You need to tell him explicitly, using an IEqualityComparer :
public class ApplicationsDetailsModelComparer : IEqualityComparer<ApplicationsDetailsModel> {
public bool Equals(ApplicationsDetailsModel first, ApplicationsDetailsModel second) {
return first.AppNum == second.AppNum;
}
public int GetHashCode(ApplicationsDetailsModel applicationsDetailsModel) {
return applicationsDetailsModel.AppNum.GetHashCode();
}
}
Then, you use it like this :
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelComparer ()).ToList();
If AppNum isn't an unique value in your collection (like a primary key), feel free to adapt the comparer class to your needs.
jgauffin's answer on the question that you linked to sums it up:
http://stackoverflow.com/a/13361682/89092
Except requires that Equals and GetHashCode is implemented in the traversed class.
The problem is that the Except method does not now how to compare instances of ApplicationsDetailsModel
You should implement GetHashCode in ApplicationsDetailsModel to create a way to uniquely identify an instance
You should implement Equals in ApplicationsDetailsModel and use the result of GetHashCode to return whether or no the instances should be considered "Equal". It is probably best to do this by implementing the IEquatable interface: http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx
When you perform these steps, the Except method will work as expected

Categories

Resources