I have two classes and their variables are exactly the same.(To avoid prolonging the question, I don't explain why I'm using the same class.) I am comparing the same variables in these two classes with Reflection. The function returns true if there is a variable whose value has changed.. However, this function I wrote does not make the comparison correctly if there is a list in the class. Returns true for identical and unchanged lists, but the result should be false
Assume the list is full and the same values
CLASS ONE
CLASS TWO
ID = 5
ID = 5
Number = 10
Number = 10
List a
List a
private bool Compare(Class A, Class B)
{
A.GetType().GetProperties().ToList().ForEach(p =>
{
B.GetType().GetProperties().ToList().ForEach(p2 =>
{
if (p.Name == p2.Name)
{
if
(!p.GetValue(A).Equals(p2.GetValue(B)))
{
result = true;
}
}
}
);
});
return result;
}
First, I recommend that you implement IEquatable https://learn.microsoft.com/en-us/dotnet/api/system.iequatable-1?view=net-6.0.
Then, it's hard to be 100% sure, but your problement is probably that return true when the values are not equal.
Finally, your problem with the lists is probably because equality with lists are using the reference to the list not the values contained by them.
Since you're using reflexion I don't think it's best to handle the list case explicitly. One way to do it would be to do a wrapper class that implements the Equals() method with something like this :
if (listA.Except(listB).Any())
https://stackoverflow.com/a/9524717/12330678
Related
So I have a function named "DisplayTextBlock" which displays TextBlock. I have made a list of this function, though whenever I try to find index of function in that List, I get -1.
public void DisplayTextBlock(TextBlock block)
{
Doing something here.
}
int myActiveTextIndex;
textDisplay.Add(() => DisplayTextBlock(block1 = new TextBlock("1. some text here")));
textDisplay.Add(() => DisplayTextBlock(block2 = new TextBlock("2. some text here")));
textDisplay.Add(() => DisplayTextBlock(block3 = new TextBlock("3.some text here")));
textDisplay.Add(() => DisplayTextBlock(block4 = new TextBlock("4.some text here")));
List<Action> textDisplay = new List<Action>();
myActiveTextIndex = textDisplay.IndexOf(() => DisplayTextBlock(block3));
Why does it output -1?
Delegates have this notion of equality, as stated in documentation:
The methods and targets are compared for equality as follows:
If the two methods being compared are both static and are the same
method on the same class, the methods are considered equal and the
targets are also considered equal.
If the two methods being compared are instance methods and are the
same method on the same object, the methods are considered equal and
the targets are also considered equal.
Otherwise, the methods are not considered to be equal and the targets
are also not considered to be equal.
You are using anonymous methods, like () => DisplayTextBlock(block3), and even if anonymous method A is doing the same thing as anonymous method B (which is by the way not the case in your code) - they are still compiled into different methods. That means they will always violate same method in the comparision above, and are never equal.
If you want to store delegates in some kind of a list for later retrieval - don't rely on delegate equality comparision - use Dictionary and use appropriate key, by which you can retrieve associated delegate later.
-1 means it cannot find the item in the list https://learn.microsoft.com/en-us/dotnet/api/system.string.indexof?view=netcore-3.1
I tried to followed the Guidelines from MSDN and also referred to This great question but the following seems to not behave as expected.
I'm trying to represent a structure similar to a FQN where as if P1 was listed before P2, P2 would only exist in the same set as P1. Like how scope works.
On the subject of GetHashCode()
I have a class with properties like this.
class data{
public readonly string p1, p2;
public data(string p1, string p2) {
this.p1 = p1;
this.p2 = p2;
}
public override int GetHashCode()
{
return this.p1.GetHashCode() ^ this.p2.GetHashCode();
}
/*also show the equal for comparison*/
public override bool Equals(System.Object obj)
{
if (obj == null)
return false;
data d = obj as data;
if ((System.Object)d == null)
return false;
/*I thought this would be smart*/
return d.ToString() == this.ToString();
}
public override string ToString() {
return "[" + p1 +"][" + p2+ "]";
}
}
In a Dictionary (dict) I use data as a key, so this would make the scope look like d1.p1.p2 (or rather p2 of p1 of d1, however you prefer to imagine it)
Dictionary<data,int> dict = new Dictionary<data,int>();
I've examined the behavior when d1.p1 and another d2.p1 are different, the operation resolves correctly. However when d1.p1 and d2.p1 are the same and p2 of d1 and d2 are different I observe the following behavior.
data d1 = new data(){ p1="p1", p2="p2" };
data d2 = new data(){ p1="p1", p2="XX" };
dict.add(d1, 0);
dict.add(d2, 1);
dict[d1] = 4;
The result is that both elements are 4
Is GetHashCode() overridden correctly?
Is Equals overridden correctly?
If they are both fine how/why does this behavior happen?
On the subject of a Dictionary
In the watch window (VS2013), I have my dictionary's key list show me, instead of a single key per index as I would normally expect, each property of my data object is a key for a single index. So I'm not sure if in there lay the problem or I'm just misunderstanding the Watch window's representation of an object as a key. I know how that is the way VS will display an object but, I'm not certain that's how I would expect it to be displayed for a key in a dictionary.
I thought GetHashCode() was a Dictionary's primary "comparison" operation, is this always correct?
What's the real "Index" to a Dictionary where the key is an object?
UPDATE
After looking at each hash code directly I noticed that they do repeat. Yet the Dictionary does not determine that the index exists. Below is an example of the data I see.
1132917379 string: [ABC][ABC]
-565659420 string: [ABC][123]
-1936108909 string: [123][123]
//second loop with next set of strings
1132917379 string: [xxx][xxx]
-565659420 string: [xxx][yyy]
//...etc
Is GetHachCode() overridden correctly?
Sure, for some definition of "correct". It may not be overridden well, but it's not an incorrect implementation (since two instances of the class that are considered equal will hash to the same value). Of course with that requirement you could always just return 0 from GetHashCode and it would be "correct". It certainly wouldn't be good.
That said your particular implementation is not as good as it could be. For example, in your class, the order of the strings matter. I.e. new data( "A", "B" ) != new data( "B", "A" ). However, these will always hash equal because your GetHashCode implementation is symmetric. Better to break the symmetry in some fashion. For example:
public int GetHashCode()
{
return p1.GetHashCode() ^ ( 13 * p2.GetHashCode() );
}
Now it's less likely that there will be a collision for two instances that are not equal.
Is Equal overridden correctly?
Well, it can definitely be improved. For example, the first null check is redundant and so is the cast to object in the second comparison. The whole thing would probably be better written as:
public bool Equals( object obj )
{
var other = obj as data;
if( other == null ) return false;
return p1 == obj.p1 && p2 == obj.p2;
}
I also removed the call to ToString since it doesn't significantly simplify the code or make it more readable. It's also an inefficient way of performing the comparison, since you have to construct two new strings before the comparison even happens. Just comparing the members directly gives you more opportunities for an early out and, more importantly, is a lot easier to read (the actual equality implementation doesn't depend on the string representation).
If they are both fine how/why does this behavior happen?
I don't know, because the code you've given won't do this. It also won't compile. Your data class has two readonly fields, you can't assign those using an initializer list as you've shown in your last code snippet.
I can only speculate as to the behavior you're seeing, because nothing you've shown here would result in the behavior as described.
The best advice I can give is to make sure that your key class is not mutable. Mutable types will not play nice with Dictionary. The Dictionary class does not expect the hash codes of objects to change, so if GetHashCode depends on any part of your class that is mutable, it's very possible for things to get very messed up.
I thought GetHachCode() was a Dictionary's primary "comparison" operation, is this always correct?
Dictionary only uses GetHashCode as a way to "address" objects (to be specific the hash code is used to identify which bucket an item should be placed in). It doesn't use it directly as a comparison necessarily. And if it does, it can only use it to determine that two objects are not equal, it can't use it to determine if they are equal.
What's the real "Index" to a Dictionary where the key is an object?
I'm not entirely sure what you're asking here, but I'm inclined to say that the answer is that it doesn't matter. Where the item goes is unimportant. If you care about that sort of thing, you probably shouldn't be using a Dictionary.
Is GetHashCode() overridden correctly?
No. You allow passing null for p1 or p2 and null.GetHashCode() throws a NullReferenceException which is not allowed in GetHashCode. Either forbid passing null, or make GetHashCode return an int for nulls (zero is OK).
You are also XORing unaltered ints; this means every class you create that contain two of the same values will have a hashCode of zero. This is a very common collision; typically one multiplies each hashcode by a prime number to avoid this.
Is Equals overridden correctly?
No. The page you linked to is the non-generic Equals used by System.Collections.HashTable. You are using the generic System.Collections.Generic.Dictionary, which uses the generic IEquatable<T>. You need to implement IEquatable<data> as explained in the accepted answer to the SO question you posted.
It is true that IEquatable<data> will fall back to Equals(System.Object obj) if not defined, but do not rely on that behavior. Also, converting ints to strings to compare them is not “smart”. Any time you feel you should write a comment excusing something as “smart” you are making a mistake.
A better implementation of 'data` would be:
public class MatPair : IEquatable<MatPair>
{
public readonly string MatNeedsToExplainWhatThisRepresents;
public readonly string MatNeedsToExplainThisToo;
public MatPair(string matNeedsToExplainWhatThisRepresents,
string matNeedsToExplainThisToo)
{
if (matNeedsToExplainWhatThisRepresents == null) throw new ArgumentNullException("matNeedsToExplainWhatThisRepresents");
if (matNeedsToExplainThisToo == null) throw new ArgumentNullException("matNeedsToExplainThisToo");
this.MatNeedsToExplainWhatThisRepresents = matNeedsToExplainWhatThisRepresents;
this.MatNeedsToExplainThisToo = matNeedsToExplainThisToo;
}
[Obsolete]
public override bool Equals(object obj)
{
return Equals(obj as MatPair);
}
public bool Equals(MatPair matPair)
{
return matPair != null
&& matPair.MatNeedsToExplainWhatThisRepresents == MatNeedsToExplainWhatThisRepresents
&& matPair.MatNeedsToExplainThisToo == MatNeedsToExplainThisToo;
}
public override int GetHashCode()
{
unchecked
{
return MatNeedsToExplainWhatThisRepresents.GetHashCode() * 31
^ MatNeedsToExplainThisToo.GetHashCode();
}
}
public override string ToString()
{
return "{" + MatNeedsToExplainWhatThisRepresents + ", "
+ MatNeedsToExplainThisToo + "}";
}
}
I have a class named ACTIVITY. This class contains a list of Laps, and each Lap has a collection of TRACPOINTS.
ACTIVITY --many--> LAPS ---many --> TRACPOINTS.
Whenever I fLatten the TRACPOINTS collection I get the list of all the TRACPOINTS. But when I modify those of course the originals don't get modified since it's a copy.
Is there any way that whatever change I made to the flattened tracpoints gets changed in the Tracpoints list for each lap?
As long as TRACPOINT is a struct, it is not possible in any reasonable way.
Whenever you assign a value of struct variable or field to another variable or field, its contents are copied. The same holds for passing it as a method argument or returning it from a method, its value is copied. This is value semantics [1]. Compare this to atomic types like int, which have value semantics too. You would probably expect the following code to print 2, not 3.
static function Change(int j) { j = 3; }
static void Main(string[] args) {
int i = 2;
Change(i);
System.Console.WriteLine(i);
}
If you do SelectMany, each value from the collection is probably assigned to some temporary local variable and then returned from the iterator (SelectMany), therefore it is copied and in fact possibly copied many times before it comes out from the iterator. So what you are updating is a copy of the struct. Like in the example, you're not changing variable i, but its copy stored in variable j.
This is why structs should be immutable. Instead of having properties with getters and setter in your struct, they should have only getters. For changing values of properties of a struct, you can implement methods that copy the whole original struct, change the value of the desired property and return the new struct instance. In fact, again, its copy will be returned. Example:
struct S {
int f;
public int F { get { return this.f; } }
public S SetF(int newVal) {
var s = new S();
s.f = newVal;
return s;
}
}
var x = new S();
x = x.SetF(30);
That said, it could be possible to achieve what you want with pointers and unsafe C#, but believe me, it will be way easier to change your structs to classes, so that they have reference semantics instead of value semantics, or keep them structs, but make them immutable and do not use Linq, but old school loops. If you want to use Linq for something like SelectMany in such scenario, you probably do not care about performance difference between structs and classes so much...
[1] http://msdn.microsoft.com/en-us/library/aa664472(v=vs.71).aspx
So, I'm doing an assignment for my C# class and I have a list of objects. These objects have an 'int rand' field which is assigned a random number. I then wanted to re-sort the objects in the list based on this rand field.
I found this article:
http://www.developerfusion.com/code/5513/sorting-and-searching-using-c-lists/
And it helped. I modified this line to fit my code:
people.Sort(delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age); });
And it does what I want.
What I want to know is: how does it work? That looks very confusing to me.
In fact Sort Method should sort base on some comparison, in your current code you passed comparison as delegate, you can also embed it in class definition to reduce code complexity, In fact it just needed to implement IComparable for your Person class:
public class Person : IComparable
{
public int age { get; set; }
public int CompareTo(object obj)
{
var person = obj as Person;
if (person != null)
{
if (age > person.age)
return 1;
else if (age == person.age)
return 0;
return -1;
}
return 1;
}
}
then simply use sort without delegates.
If you use Lambda notation with it gets a little easier to read IMO:
people.Sort((p1, p2) => p1.age.CompareTo(p2.age));
When you use the sort method you are sorting the list, but the method needs to know what to sort by, and this is where the delegation becomes handy as you can use the sort method to specify any sorting you want. You are looking at person 1 and person 2 and are ordering by age. If you wanted to sort by something else like a Name (If you had a Name property), you would write it as:
people.Sort((p1, p2) => string.Compare(p1.Name, p2.Name));
the list will use the function passed in (the return p1.age.CompareTo(p2.age); part) to compare the different objects in the list. It basically allows you to "teach" the list how you want the items compared.
The list will call your function, passing in 2 instances of the class that should be compared. you return -1 to say the 1st is less than the 2nd, 0 to say they are equal, and 1 to say the 2nd is greater. Your example just passes the call on to the built in comparison (that returns the same -1, 0, 1 pattern) for whatever type the age variable is, most likely an integer.
In order to sort, you need to be able to figure out if one item goes before or after another thing. It makes sense that this "comparator" would be a function or method as it compartmentalizes the knowledge away.
If you look at the documentation for CompareTo you'll notice that it's intended to return -1 (B goes before A), 0, (A and B are equal) or 1 (B goes after A).
The delegate keyword in this instance creates an anonymous function which is used as the comparator, and the body of that function calls CompareTo to compare the age property of the two people involved and return the result.
The result of calling this method on every potential pair of items (or some subset - I'm not sure exactly how Sort is implemented) is then used internally by the Sort method to figure out where to place the resulting item (in front of or behind of p2) in this example.
List.Sort uses Quick sort algo to sort the list. The worst case complexity is O(n ^ 2). Which means, in worst case, the delegate you provided will be called n ^ 2 times, where n is the number of items in list. Delegate is like pointer to function.
It passes the two objects it wishes to compare, and the delegate you provided will return with -1, 0, or 1. If its -1 it means that p1 is lesser then p2, if 0 it means both objects are same, if 1 it means p1 is greater then p2. So, in the end, the delegate you provide and the values it returns will decide whether the list contains objects in descending or ascending order.
Lets divide the problem so that you can understand each piece separately:
The Sort method:
This one takes a delegate, that contains the "how to" compare two elements of the list.
As soon as you teach the list how to compare to elements, then it can sort all elements, by comparing them in pairs.
The inline delegate
A inline delegate is the declaration of method, that does something.
delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age);
This delegate is telling how to compare two Person objects. You are telling this to the compiler: to compare p1 with p2, you should compare p1.age with p2.age.
Joining things
The following line of code contains both elements, the sort method, and the "how to" compare two People objects.
people.Sort(delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age); });
So now it knows how to sort the list.
I had a need for a method that could take a collection of strings, and replace all occurrences of a specific string with another.
For example, if I have a List<string> that looks like this:
List<string> strings = new List<string> { "a", "b", "delete", "c", "d", "delete" };
and I want to replace "delete" with "", I would use this LINQ statement:
strings = (from s in strings select (s=="delete" ? s=String.Empty : s)).ToList();
and it works great. But then I figured I should make it an extension method, since I'd likely use it again later. In this case, I just want to write the following:
strings.ReplaceStringInListWithAnother( "delete", String.Empty);
While my code compiles, and the LINQ statement works inside of the extension method, when I return the collection reverts back to its original contents:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
my_list = (from s in my_list select (s==to_replace ? s=replace_with : s)).ToList();
}
So it would seem that I just modified a copy of the List... but when I looked at the code for Pop, it modifies the collection similarly, yet the changes stick, so my assumption was that my method's parameter declarations are correct.
Can anyone explain what I am doing wrong here?
The LINQ statement you wrote does not modify the collection, it actually creates a new one.
The extension method you wrote creates this new collection and then discards it. The assignment is redundant: you’re assigning to a local parameter, which goes out of scope immediately after.
When you’re calling the method, you’re also discarding its result instead of assigning it back.
Therefore, you should write the method like this:
public static List<string> ReplaceStringInListWithAnother(
this List<string> my_list, string to_replace, string replace_with)
{
return (from s in my_list select
(s == to_replace ? replace_with : s)).ToList();
}
and the call like this:
strings = strings.ReplaceStringInListWithAnother("delete", "");
By the way, you can make the function more useful by making it generic:
public static List<T> ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return (from s in my_list select
(s.Equals(to_replace) ? replace_with : s)).ToList();
}
This way you can use it for other things, not just strings. Furthermore, you can also declare it to use IEnumerable<T> instead of List<T>:
public static IEnumerable<T> ReplaceItems<T>(this IEnumerable<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return from s in my_list select (s.Equals(to_replace) ? replace_with : s);
}
This way you can use it for any collection of equatable items, not just List<T>. Notice that List<T> implements IEnumerable<T>, so you can still pass a List into this function. If you want a list out, simply call .ToList() after the call to this one.
Update: If you actually want to replace elements in a list instead of creating a new one, you can still do that with an extension method, and it can still be generic, but you can’t use Linq and you can’t use IEnumerable<T>:
public static void ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
for (int i = 0; i < my_list.Count; i++)
if (my_list[i].Equals(to_replace))
my_list[i] = replace_with;
}
This will not return the new list, but instead modify the old one, so it has a void return type like your original.
Here's a hint: what do you expect the below code to do?
void SetToTen(int y)
{
y = 10;
}
int x = 0;
SetToTen(x);
Hopefully, you understand that the SetToTen method above does nothing meaningful, since it only changes the value of its own local variable y and has no effect on the variable whose value was passed to it (in order for that to happen, the y parameter would have to be of type ref int and the method would be called as SetToTen(ref x)).
Keeping in mind that extension methods are really just static methods in fancy clothes, it should be clear why your ReplaceStringInListWithAnother is not doing what you expected: it is only setting its local my_list variable to a new value, having no effect on the original List<string> passed to the method.
Now, it's worth mentioning that the only reason this is not working for you is that your code works by setting a variable to a new object*. If you were to modify the List<string> passed to ReplaceStringInListWithAnother, everything would work just fine:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
for (int i = 0; i < my_list.Count; ++i)
{
if (my_list[i] == to_replace)
{
my_list[i] = replace_with;
}
}
}
It's also worth mentioning that List<string> is an overly restrictive parameter type for this method; you could achieve the same functionality for any type implementing IList<string> (and so I'd change the my_list parameter to be of type IList<string>).
*Reading your question again, it seems clear to me that this is the main point of confusion for you. The important thing you have to realize is that by default, everything in C# is passed by value. With value types (anything defined as a struct -- int, double, DateTime, and many more), the thing that's passed is the value itself. With reference types (anything that's defined as a class), the thing that's passed is a reference to an object. In the latter case, all method calls on references to objects of mutable types do actually affect the underlying object, since multiple variables of reference type can point to the same object. But assignment is different from a method call; if you assign a reference to an object that has been passed by value to some new reference to an object, you are doing nothing to the underlying object, and therefore nothing is happening that would be reflected by the original reference.
This is a really important concept that many .NET developers struggle with. But it's also a topic that's been explained thoroughly elsewhere. If you need more explanation, let me know and I'll try to dig up a link to a page that makes all of this as clear as possible.
You haven't shown the code for "Pop" so it's hard to know what you mean. You talk about "when I return the collection" but you're not returning anything - the method has a void return type.
LINQ typically doesn't change the contents of an existing collection. Usually you should return a new collection from the extension method. For example:
public static IEnumerable<string> ReplaceAll
(this IEnumerable<string> myList, string toReplace, string replaceWith)
{
return toReplace.Select(x => x == toReplace ? replaceWith : x);
}
(I've made it more general here - you shouldn't start materializing lists unless you really need to.)
You'd then call it with:
strings = strings.ReplaceAll("delete", "").ToList();
... or change the type of string to IEnumerable<string> and just use
strings = strings.ReplaceAll("delete", "");