Why does this code result in both shipment.Items.Count and combinedShipment.Items.Count equal to zero?
private static InboundShipment CombineLikeIsbns(InboundShipment shipment)
{
// shipment.Items has a count of 3
var distinctIsbns = shipment.Items.Select(i => i.ISBN).Distinct().ToList();
var combinedShipment = shipment;
combinedShipment.Items = new List<InboundShipmentItem>();
// Now both combinedShipment and shipment have an empty List in the .Items property
...
return combinedShipment;
}
[EDIT]
And what can I do to avoid having shipment.Items set to new List when I set combinedShipment.Items to the same?
This statement:
var combinedShipment = shipment;
copies the value of shipment into combinedShipment. Assuming InboundShipment is a class, the value of shipment is a reference - not an object itself.
So now we have two variables which both refer to the same object. It doesn't matter which variable you use to make a change to the object - the change will be visible via both variables.
If you want to create a new "copy" of the original object, you'll have to do that explicitly. It's hard to know exactly what you'd need to do here, as you haven't given us much information about the InboundShipment type.
See my article on value types and reference types for more details. Note that this is a vital part of C# and .NET, and you should become confident on it before going further - advanced topics such as LINQ (with its lambda expressions, deferred execution etc) will be hard to understand until you've got a good handle on the basics.
The line
var combinedShipment = shipment;
sets the combinedShipment reference to point at the same instance as shipment. So when you clear the items on combinedShipment, it clears them for that one single instance.
The assignment var combinedShipment = shipment; causes both combinedShipment and shipment to refer to exactly the same object. It's a little bit like sticking two different labels on the same cardboard box.
So the following line where you take all the items out of the box labeled combinedShipment also causes the box labeled shipment to be emptied. Because they're just the same box with two different labels.
If you want to create a new shipment object that has different items, you'll need to start by doing exactly that: Create a new shipment object.
var combinedShipment = new InboundShipment();
The actual code might not be able to look exactly like that. Assuming you want some of combinedShipment's properties to be the same as shipment's, you'll have to manually make sure that happens. Depending on how InboundShipment is designed, that will require either passing the desired values into the constructor, setting the desired values via properties, or a mix of both.
Related
I am trying to add unit tests to my project. Some of these tests are checking if a list of objects does of does not contain an object. For checking if a list contains an object i've tried Assert.Contains(MyList, ExpectedObject), but it still gives an error that says that the list does not contain this object. Even when i debug the test i can see that the object is correctly added to the list.
The same happens with Assert.DoesNotContain(MyList, ExpectedObject). When i remove an item from the list and do this check it does say that it not in the list. But when i no longer remove the item, it still says that it is no longer in the list. Even though it is still in the list.
When i try it with a test list:List<string>. and do the same operations of adding and removing items, and then checking if these items are in the list or not. It does work.
Maybe Assert.Contains does not work for lists of objects. But the compiler does not give any errors. And i've also already checked if the ExpectedObject is the same type as the objects in the list.
Is there maybe another way of checking if an object is or isn't in a list.
any help is appreciated.
In your test, is ExpectedObject the actual object in the list or an object with the same values? In C# two objects with the same property values are not actually equal. I suspect this is why your test is failing. Two strings with the same value are considered equal because the string object implements the Equals method (and some more), like #dorukerenaktas points out.
There's multiple ways to go about this. The easiest is by checking if an object with the expected property values is in the collection.
There's an overload of Assert.Contains that allows you to specify a predicate, for example:
Assert.Contains(MyList, item => item.Id == expectedId)
Another option is to override the Equals method on your object, like #dorukerenaktas explains, but I would only recommend that if it really makes sense for your class. I would definitely not do that just so you can use this in a test.
Generally in Java and C# implementation of contains methods for object lists compare them by equals method. If equals method if not specified for the object by default it will look for object unique id or memory address, it means even if there were 2 objects with all same fields can be different. Because they created separately and allocated different ram addresses. If you want to compare objects override equals method. This will allow contains method to compare objects with each other using your custom comparison method.
Example:
Let say you have a Person object with fields like id, name, mail etc. If you want objects to be equal if their id's are same you can use:
// They are same person if their id is same
public override bool Equals(Object obj)
{
Person personObj = obj as Person;
if (personObj == null)
return false;
else
return idNumber.Equals(personObj.idNumber);
}
I have faced a similar problem before and I used fluentAssertions to solve it.
So for example if you have a list of objects called myList, this snipped should do the trick.
myList.Should().Contain(expectedItem);
There is more info on collections here: https://fluentassertions.com/collections/
The other option is to loop through the list and check if any of the objects are equal to your object. When doing this, if you use the ShouldBeEquivalentTo() method you will not need to check equality of every property. This is very useful if your object is large or nested, since this method checks each property recursively.
actual.Should().BeEquivalentTo(expected);
There is more information on this here: https://fluentassertions.com/objectgraphs/
I like using fluentAssetions because it makes my tests and assertions more readable, and also provides very clear messages when errors do occurs or assertions fail, so you find the problem faster.
I am not sure how to even title or ask this question, so apologies for any confusion.
I need to get the value of the Id from the first list in Model.Content.GetPropertyValue("SlidePanel"). I've tried many, many, many thing with my troubles usually being that "You can't do this because it's an Object". In the image below, I want to get the Id Value of "1092" as a String.
-----EDIT-------
I was able to get the value with the code below. Casted the list, grabbed the first list since it would always be that option (I wrapped it in an if, but removed it in this example), then I was able to specify the property I needed and converted as needed.
If I sound like I don't speak this language fluently, it's because I'm still fresh to development. Thanks for everyone who helped.
dynamic slidePanelObject = Model.Content.GetProperty("SlidePanel").Value;
List<object> slidePanelCast = ((IEnumerable<object>)slidePanelObject).Cast<object>().ToList();
dynamic slidePanelFirst = slidePanelCast.First();
var slidePanelId = slidePanelFirst.Id;
string slidePanelString = slidePanelId.ToString();
Model.Content.GetPropertyValue is probably returning an System.Object, so you'll need to cast your temp var to a List<T> type of some kind before you can access it like a list.
Without knowing all the types involved, here's some code that you could modify:
var temp = Model.Content.GetPropertyValue("SlidePanel") as List<TYourType>;
I am building a control in xamarin forms that binds to a list of objects. To get this binding to work I need to use observable collections (otherwise propertychanged methods don't fire).
I noticed a really frustrating interaction as a result of needing to use OC's as opposed to lists. Whenever the binded OC updates, the values in my controls are automatically updated, even if they are just references of the OC, Here is how i am copying the OC.
//Internal list of events
private List<EventItem> _events;
void OnEventsChanged(ObservableCollection<EventItem> eventsCollection)
{
//Error handle
List<EventItem> events = eventsCollection.ToList();
//Do something
_events = events;
}
The problem comes when the OC updates, I want to check for new/deleted AND altered objects. The issue is that when the OC updates, it is updating the internal list (_events) aswell. This means when I go to do comparisons between the old & new values, they are the same.
Honestly I don't really understand how c# handles copying references of objects around, I had a similar issue a while back with DateTime.Now being calculated as opposed to copying the value of the already initialised object.
var time = DateTime.Now;
await Task.Delay(1000);
var time2 = time; //This is 1 second later than time, not the value of time (which is what I wanted)
I have used Objective-C in the past and that has the concept of MutableCopy where you can assign a new list from an existing one, they have the same values but aren't linked.
How can I do this in C# so that my controls internal list is only updated by me and not the OC?
Thanks
That's perfectly normal. If I have enough time, I'll try to explain it to you.
In a nutshell, the observableList (or a List) is a list of reference to the objects and not a list of objects. The thing is that the objects are not copied inside a list but the list contains a reference to the different objects. That means that if you do something like ToList(), you get another list of references to the exact same objects.
Now to solve your problem. Just create a new list with new objects with something like
var newList = oldList.Select(x => new Model(x)).ToList();
And of course the Model class has a constructor that accept a Model as a parameter and copy the properties.
When you write _events = events;, you create not a new object, but a reference for the same object. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/index .
You should to clone (create a copy of object itself) as it mentioned in comment by #Matt.
This question is connected (but NOT duplicate) of this one. Consider that I am fairly new to C#.
I would like, if possible, to take the handle of a member of an object that has not been instantiated jet, in order to use it later on. Following previous question, I would like to do something like
List<Action<YourClass>> lst = new List<Action<YourClass>>;
lst.Add(x => x.Member1);
lst.Add(x => x.Member2);
Member1 and Member2 are not supposed to be static member, as their value depend on the state of the object they are member of. Basically I want the handle of their "name", so that I can use it later on when the objects are instantiated. I was thinking about an approach based on string which value is the member name, but maybe there is a better way?
Thanks.
I'm not sure if i understand you right. At first you need to create an instance from your list.
List<Action<YourClass>> lst = new List<Action<YourClass>>;
Else your Add will broke with NullReference-Exception. What you are using in your Add is called anonymus function because the handle isn't saved. If you would like to store this you need a delegate. On this delegate you can call the Invoke-Methode to call it. You are allowed to create your on delegates as well as using predefined like Action.
Here is a small example without any sence, but maybe clarify:
var action = new Action<string>(x => x = x.Substring(1, 1));
//Do some other stuff
action.Invoke("Hallo");
Note that the used var keyword. It detects the result of new Action and take the type of this. In this case it holds Action.
Further note that Action is a predefined delegate. An other would be Func which got one return value. If you need other behaviour you easily can create your own delegates. For this you should read the link.
I found the solution thanks to Henk comment:
Func<myObj, Vector> getVect = new Func<myObj, Vector>
getVect= (myObj => myObj.objVector);
where objVector is NOT a method, but a member of the myObj.
I call getVect in this way:
Vector a= getVect(someObj)
I'm trying to achieve the following scenarios:
Add 5 items of type T to a new Redis SET
Add 1 item of type T to an existing Redis SET
(i know SETADD doesn't care if the set is existing, but just listing my scenarios for reference)
I can see there is SetAddAsync(RedisKey, RedisValue value) and SetAddAsync(RedisKey, RedisValue[] values), but i'm not sure how to work with it (and which overload to use?)
When i've used StringSet, i simply serialize T to a byte[], then use that as the RedisValue param.
But not sure how to do it for sets.
This is what i have:
var items = values.Select(serializer.Serialize).ToArray();
await cache.SetAddAsync(key, items);
where serializer is a class which converts T to a byte[]
It is basically identical to how you would use StringSet. The only difference is that when setting a string, it only makes sense to set one value - but when adding to a set, you might want to add 1 or more elements at a time.
If you're adding one element, just use:
db.SetAdd[Async](key, serializedValue);
If you want to add a larger number of items to the set in one go, then first get the serialized items, for example:
var items = Array.ConvertAll(values, value => (RedisValue)serializer.Serialize(value));
or to tweak your existing code:
var items = values.Select(value => (RedisValue)serializer.Serialize(value)).ToArray();
The important difference here is that I expect your original code is ending up with a byte[][], where-as you need a RedisValue[]. The (RedisValue) cast in the above should fix that for you.
Then call:
db.SetAdd[Async](key, serializedValues);
This corresponds to the variadic form of SADD.