I need to compare two objects of the same type but with a lot of prop
return string.Equals(x.Name, y.Name) &&
x.Price == y.Price &&
string.Equals(x.Species, y.Species) &&
x.AgeEnforced == y.AgeEnforced &&
x.MinimumAge == y.MinimumAge &&
string.Equals(x.WeightRange, y.WeightRange) &&
x.MinimumWeight == y.MinimumWeight
The list goes on up to 14 props
A hint on how can I lose && operator?
If your class has 14 properties and all of them have to be compared to ensure equality, all of these checks have to be made somewhere. No matter if you put them into a (maybe static) helper method, the Equals-method, a class that implements IEqualityComparer (IMHO the best choice), an extension method or whatever else comes to your mind, you have to write down all of these checks once.
Instead of writing these checks on yourself you can use some reflection stuff (or a library that makes use of it) by iterating over all properties, but that's normally not the best choice, cause it is slower and equality checks are tend to be called very often (sort, hashset, etc.). So take the pain and write the checks down.
If you think these are too many checks, then maybe your object is to fat and has to much properties. Maybe it needs a deeper hierarchy by using classes which are representing a part of the whole thing and you have a top class that has as property a child class and then you write the compare method for each child class individually and the top class just calls these comparers for its child classes.
Answer to A hint on how can i lose && operator?
if (string.Equals(x.Name, y.Name) == false) return false;
if (x.Price != y.Price) return false
// ... others
return true;
This code must be somewhere. If this is only place where this code exist this is ok in my opinion. Bu if it exists in many places then you can move it to some helper fuction or override Equals() method in your object. MSDN info.
Example how to oveeride and use Equals():
public class MyObject
{
public string Name { get; set; }
public decimal Price { get; set; }
public override bool Equals(object obj)
{
MyObject o = obj as MyObject;
if (o == null)
return false;
if (this.Name != o.Name)
return false;
return true;
}
/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>
/// A hash code for the current object.
/// </returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public class Program
{
static public void Main()
{
MyObject o1 = new MyObject()
{
Name = "a",
Price = 1
};
MyObject o2 = new MyObject()
{
Name = "b",
Price = 1
};
MyObject o3 = new MyObject()
{
Name = "a",
Price = 1
};
Console.WriteLine("o1 == o2: {0}", o1.Equals(o2));
Console.WriteLine("o1 == o3: {0}", o1.Equals(o3));
Console.ReadKey();
}
}
Result is:
o1 == o2: False
o1 == o3: True
For me, && or || are pretty short already. Your problem lies not in the operator itself, but in the way you are doing the comparison of 14+ properties.
Instead of writing all the property-comparisons by hand, you can try automating it.
var props_string = new List<Func<MyObject, string>>();
props_string.Add(foo => foo.Name);
props_string.Add(foo => foo.Species);
//..
var props_double = new List<Func<MyObject, double>>();
props_double.Add(foo => foo.Price);
//..
Now, having them listed, you can ran a loop over it
MyObject first = ...;
MyObject second = ...;
bool areEqual = true;
foreach(var prop in props_string)
if(!string.Equals(prop(first), prop(second)))
areEqual = false;
foreach(var prop in props_double)
if(prop(first) != prop(second))
areEqual = false;
return areEqual;
The positive side is that even if there were 100 properties, one or two (or more) loops would fly over it.
Please note that this code is not optimized and pretty naive.
More natural would be a fast-exit on first difference:
foreach(var prop in props_double)
if(prop(first) != prop(second))
return false;
..and/or observing that string.equals and double!=double can all be packed as the same object.Equals method (so you don't need separate props_string, props_double etc)
..and/or observing that you don't really need to list all properties, you can get them from Reflection, so you don't need to 'define' the 100 properties in these lists. (But then, you often have some special properties that you don't want to include.. so your reflection-way would need a way to detect and skip them..)
..and/or observing that if you used struct instead of class you would get full memberwise object.Equals comparison for free. (But then, structs differ from classes in many other things..)
..and/or(...)
All these 'optimizations' are highly dependent on what you have in the rest of the 14+ comparisons. It looks fun and smart at first, but the more the types of properties vary and the more types of comparisons you need to do (string.equals with case-insensitive maybe?) the worse it will get. Sometimes 14 times &&, or 14 times if(x==y)return false isn't really that bad.
Please don't get me wrong: I do not advise you to use the way I show here. I just show you that it is possible. Don't use it unless absolutely relevant and necessary. Doing it this way may cost you much more time than you would want to.
This seems as a correct way how to do the compare.
If your aim is to be able to easily check if two different instances are equal you can override Equals() and GetHashCode().
You will be able to do:
x.Equals(y)
You can also override operator ==. In which case you can do:
x == y
Check MSDN for details and example.
Also there is no reason for you (unless you want to use any extra parameters) to use
string.Equals(x.Name, y.Name)
use simply
x.Name == y.Name
Related
I have this code which i want to change:
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Contains(path)) {
MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
currNoPairs.Add(path);
}
}
In the If part i don't want to check the path i want to check the path.Name.
So how can i use the Contains method on the properties.
the goal is to sort out all folders that have not the same name in the list of Current Directory List and New Directory List.
See - IEnumerable<T>.Contains with predicate
Those functions that take "predicates" (boolean functions that signify a match) will let you do more complex checks. In this case, you can use them to compare sub-properties instead of the top-level objects.
The new code will look something like this:
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Any(newDir => newDir.Name == path.Name)) {
// TODO: print your error message here
currNoPairs.Add(path.Name);
}
}
In reply to your comment:
Okay i understood, but whats the diffrence between any and contains then?
List<T>.Contains
This method goes through each item in the list, seeing if that item is equal to the value you passed in.
The code for this method looks a little like this (simplified here for illustration):
for(var item in yourList) {
if(item.Equals(itemYouPassedIn) {
return true;
}
}
return false;
As you see, it can only compare top-level items. It doesn't check sub-properties, unless you are using a custom type that overrides the default Equals method. Since you're using the built in DirectoryInfo types, you can't override this Equals behavior without making a custom derived class. Since there's easier ways to do this, I wouldn't recommend this approach unless you need to do it in a ton of different places.
IEnumerable<T>.Any
This method goes through each item in the list, and then passes that item to the "predicate" function you passed in.
The code for this method looks a little like this (simplified for illustration):
for(var item in yourList) {
if(isAMatch(item)) { // Note that `isAMatch` is the function you pass in to `Any`
return true;
}
}
return false;
Your predicate function can be as complicated as you want it to be, but in this case, you'd just use it to check if the sub-properties are equal.
// This bit of code defines a function with no name (a "lambda" function).
// We call it a "predicate" because it returns a bool, and is used to find matches
newDir => newDir.Name == path.Name
// Here's how it might look like if it were defined as a normal function -
// this won't quite work in reality cause `path` is passed in by a different means,
// but hopefully it makes the lambda syntax slightly more clear
bool IsAMatch(DirectoryInfo newDir) {
return newDir.Name == path.Name;
}
Since you can customize this predicate every place that you use it, this could be a better tactic. I'd recommend this style until you are doing this exact check in a bunch of places in your code, in which case a custom class might be better.
Here is how you check for property Any
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Any(dir => dir.FullName == path.FullName)) {
MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
currNoPairs.Add(path);
}
}
And by the way, your code could be written in a better way like this
var currDirsConcrete = currDirs.ToArray();
var pathsNotFound = "Following paths were not found \r\n " + string.Join("\r\n", currDirsConcrete.Where(d => d.FullName != path.FullName).ToArray());
var pathsFound = currDirsConcrete.Where(d => d.FullName == path.FullName).ToArray();
MyLog.WriteToLog(pathsNotFound, MyLog.Messages.Warning);
Note: You can skip the first line currDirsConcrete if your currDirs is already an array or a list. I did this to avoid redetermining the enumerable.
I would use linq with except and implement a DirComparator
List<DirectoryInfo> resultExcept = currDirs.Except(newDirs, new DirComparator()).ToList();
Here the IEqualityComparer<DirectoryInfo>:
public class DirComparator : IEqualityComparer<DirectoryInfo> {
public bool Equals(DirectoryInfo x, DirectoryInfo y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Name.equals(y.Name);
}
public int GetHashCode(DirectoryInfo dir)
{
//Check whether the object is null
if (Object.ReferenceEquals(dir, null)) return 0;
//Get hash code for the Name field if it is not null.
return dir.Name == null ? 0 : dir.Name.GetHashCode();
}
}
you could also use intersect if you want it the other way around.
I am trying to figure out why the following code throws a StackOverflowException (I am finally posting a StackoverflowException in SO!).
Debugging seems to point out that the p.GetValue(this) is generating further calls.
What is actually triggering the infinite call chain ? Is it because p.GetValue(this) ultimately returns an instance of the current object, and thus acts as if constructing a new instance (and every object that constructs itself within its construction will lead to Stackoverflow exceptions) ?
My intent with the following code is to have an object being capable of telling how many of its properties have null/space/empty values.
public class A
{
public string S1 { get; set; }
public string S2 { get; set; }
public int NonInitializedFields
{
get
{
int nonNullFields = 0;
var properties = this.GetType().GetProperties();
foreach (var p in properties)
{
var value = p.GetValue(this);
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
nonNullFields++;
}
return nonNullFields;
}
}
}
//the following throws a StackOverflowException (the construction line itself)
A a1 = new A1{ S1 = "aaa"};
Console.WriteLine(a1.NonInitializedFields);
P.S. My idea originally involves only simple string properties, nothing else, so whatever problems may arise with this approach with other types are not relevant.
You have a property, which, when you execute the "get" accessor, finds all the properties and fetches their value. So it executes itself, recursively.
If you only want string properties, you should check the property type before fetching the value:
var properties = GetType().GetProperties().Where(p => p.PropertyType == typeof(string));
At that point, as your NonInitializedFields property doesn't have a return type of string, it won't be executed.
Personally I would make this a method call rather than a property anyway, mind you. That would also fix the issue, as the method wouldn't find itself when looking for properties.
I would also rename it, as:
A property isn't necessarily backed by a field
A field could be explicitly initialized as null or a reference to a string containing only whitespace
A method called GetNonWhitespaceStringPropertyCount() would be more accurate, IMO. You can also make the whole implementation a LINQ query:
return GetType().GetProperties()
.Where(p => p.PropertyType == typeof(string))
.Select(p => p.GetValue(this))
.Count(v => !string.IsNullOrWhitespace((string) v));
Note that I've fixed the next issue in your code - you're meant to be counting non-null/empty values, but you're actually counting null/empty ones.
Pair<BoardLocation, BoardLocation> loc = new Pair<BoardLocation, BoardLocation>( this.getLocation(), l );
if(!this.getPlayer().getMoves().Contains( loc )) {
this.getPlayer().addMove( loc );
}
I'm using a Type I have created called "Pair" but, I'm trying to use the contains function in C# that would compare the two types but, I have used override in the Type "Pair" itself to compare the "ToString()" of both Pair objects being compared. So there are 4 strings being compared. The two Keys and two value. If the two Keys are equal, then the two values are compared. The reason why this makes sense is the Key is the originating(key) location for the location(value) being attacked. If the key and value are the same then the object should not be added.
public override bool Equals( object obj ) {
Pair<K, V> objNode = (Pair<K, V>)obj;
if(this.value.ToString().CompareTo( objNode.value.ToString() ) == 0) {
if(this.key.ToString().CompareTo( objNode.key.ToString() ) == 0) {
return true;
} else
return false;
} else {
return false;
}
}
The question is, Is there a better way to do this that doesn't involve stupid amounts of code or creating new objects for dealing with this. Of course if any ideas involve these, I am all ears. The part that confuses me about this is, perhaps I dont understand what is going on but, I was hoping that C# offered a method that just equivalence of values and not the object memory locations and etc.
I've just ported this from Java as well, and it works exactly the same but, I'm asking this question for C# because I'm hoping there was a better way for me to compare these objects without using ToString() with generic Types.
You can definitely make this code a lot simpler by using && and just returning the value of equality comparisons, instead of all those if statements and return true; or return false; statements.
public override bool Equals (object obj) {
// Safety first: handle the case where the other object isn't
// of the same type, or obj is null. In both cases we should
// return false, rather than throwing an exception
Pair<K, V> otherPair = objNode as Pair<K, V>;
if (otherPair == null) {
return false;
}
return key.ToString() == otherPair.key.ToString() &&
value.ToString() == otherPair.value.ToString();
}
In Java you could use equals rather than compareTo.
Note that these aren't exactly the same as == (and Equals) use an ordinal comparison rather than a culture-sensitive one - but I suspect that's what you want anyway.
I would personally shy away from comparing the values by ToString() representations. I would use the natural equality comparisons of the key and value types instead:
public override bool Equals (object obj) {
// Safety first: handle the case where the other object isn't
// of the same type, or obj is null. In both cases we should
// return false, rather than throwing an exception
Pair<K, V> otherPair = objNode as Pair<K, V>;
if (otherPair == null) {
return false;
}
return EqualityComparer<K>.Default.Equals(key, otherPair.key) &&
EqualityComparer<K>.Default.Equals(value, otherPair.value);
}
(As Avner notes, you could just use Tuple of course...)
As noted in comments, I'd also strongly recommend that you start using properties and C# naming conventions, e.g.:
if (!Player.Moves.Contains(loc)) {
Player.AddMove(loc);
}
The simplest way to improve this is to use, instead of your custom Pair class, an instance of the built-in Tuple<T1,T2> class.
The Tuple class, in addition to giving you an easy way to bundle several values together, automatically implements structural equality, meaning that a Tuple object is equal to another if:
It is a Tuple object.
Its two components are of the same types as the current instance.
Its two components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
(from MSDN)
This means that instead of your Pair having to compare its values, you're delegating the responsibility to the types held in the Tuple.
I'm wondering if anyone as any suggestions for this problem.
I'm using intersect and except (Linq) with a custom IEqualityComparer in order to query the set differences and set intersections of two sequences of ISyncableUsers.
public interface ISyncableUser
{
string Guid { get; }
string UserPrincipalName { get; }
}
The logic behind whether two ISyncableUsers are equal is conditional. The conditions center around whether either of the two properties, Guid and UserPrincipalName, have values. The best way to explain this logic is with code. Below is my implementation of the Equals method of my customer IEqualityComparer.
public bool Equals(ISyncableUser userA, ISyncableUser userB)
{
if (userA == null && userB == null)
{
return true;
}
if (userA == null)
{
return false;
}
if (userB == null)
{
return false;
}
if ((!string.IsNullOrWhiteSpace(userA.Guid) && !string.IsNullOrWhiteSpace(userB.Guid)) &&
userA.Guid == userB.Guid)
{
return true;
}
if (UsersHaveUpn(userA, userB))
{
if (userB.UserPrincipalName.Equals(userA.UserPrincipalName, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
private bool UsersHaveUpn(ISyncableUser userA, ISyncableUser userB)
{
return !string.IsNullOrWhiteSpace(userA.UserPrincipalName)
&& !string.IsNullOrWhiteSpace(userB.UserPrincipalName);
}
The problem I'm having, is with implementing GetHashCode so that the above conditional equality, represented above, is respected. The only way I've been able to get the intersect and except calls to work as expected is to simple always return the same value from GetHashCode(), forcing a call to Equals.
public int GetHashCode(ISyncableUser obj)
{
return 0;
}
This works but the performance penalty is huge, as expected. (I've tested this with non-conditional equality. With two sets containing 50000 objects, a proper hashcode implementation allows execution of intercept and except in about 40ms. A hashcode implementation that always returns 0 takes approximately 144000ms (yes, 2.4 minutes!))
So, how would I go about implementing a GetHashCode() in the scenario above?
Any thoughts would be more than welcome!
If I'm reading this correctly, your equality relation is not transitive. Picture the following three ISyncableUsers:
A { Guid: "1", UserPrincipalName: "2" }
B { Guid: "2", UserPrincipalName: "2" }
C { Guid: "2", UserPrincipalName: "1" }
A == B because they have the same UserPrincipalName
B == C because they have the same Guid
A != C because they don't share either.
From the spec,
The Equals method is reflexive, symmetric, and transitive. That is, it returns true if used to compare an object with itself; true for two objects x and y if it is true for y and x; and true for two objects x and z if it is true for x and y and also true for y and z.
If your equality relation isn't consistent, there's no way you can implement a hash code that backs it up.
From another point of view: you're essentially looking for three functions:
G mapping GUIDs to ints (if you know the GUID but the UPN is blank)
U mapping UPNs to ints (if you know the UPN but the GUID is blank)
P mapping (guid, upn) pairs to ints (if you know both)
such that G(g) == U(u) == P(g, u) for all g and u. This is only possible if you ignore g and u completely.
If we suppose that your Equals implementation is correct, i.e. it's reflective, transitive and symmetric then the basic implementation for your GetHashCode function should look like this:
public int GetHashCode(ISyncableUser obj)
{
if (obj == null)
{
return SOME_CONSTANT;
}
if (!string.IsNullOrWhiteSpace(obj.UserPrincipalName) &&
<can have user object with different guid and the same name>)
{
return GetHashCode(obj.UserPrincipalName);
}
return GetHashCode(obj.Guid);
}
You should also understand that you've got rather intricate dependencies between your objects.
Indeed, let's take two ISyncableUser objects: 'u1' and 'u2', such that u1.Guid != u2.Guid, but u1.UserPrincipalName == u2.UserPrincipalName and names are not empty. Requirements for Equality imposes that for any 'ISyncableUser' object 'u' such that u.Guid == u1.Guid, the condition u.UserPrincipalName == u1.UserPrincipalName should be also true. This reasoning dictates GetHashCode implementation, for each user object it should be based either on it's name or guid.
One way would be to maintain a dictionary of hashcodes for usernames and GUIDS.
You could generate this dictionary at the start once for all users, which would probably the cleanest solution.
You could add or update an entry in the Constructor of each user.
Or, you could maintain that dictionary inside the GetHashCode function. This means your GetHashCode function has more work to do and is not free of side-effects. Getting this to work with multiple threads or parallel-linq will need some more carefull work. So I don't know whether I would recommend this approach.
Nevertheless, here is my attempt:
private Dictionary<string, int> _guidHash =
new Dictionary<string, int>();
private Dictionary<string, int> _nameHash =
new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
public int GetHashCode(ISyncableUser obj)
{
int hash = 0;
if (obj==null) return hash;
if (!String.IsNullOrWhiteSpace(obj.Guid)
&& _guidHash.TryGetValue(obj.Guid, out hash))
return hash;
if (!String.IsNullOrWhiteSpace(obj.UserPrincipalName)
&& _nameHash.TryGetValue(obj.UserPrincipalName, out hash))
return hash;
hash = RuntimeHelpers.GetHashCode(obj);
// or use some other method to generate an unique hashcode here
if (!String.IsNullOrWhiteSpace(obj.Guid))
_guidHash.Add(obj.Guid, hash);
if (!String.IsNullOrWhiteSpace(obj.UserPrincipalName))
_nameHash.Add(obj.UserPrincipalName, hash);
return hash;
}
Note that this will fail if the ISyncableUser objects do not play nice and exhibit cases like in Rawling's answer. I am assuming that users with the same GUID will have the same name or no name at all, and users with the same principalName have the same GUID or no GUID at all. (I think the given Equals implementation has the same limitations)
I have a class with lots of properties. A shallow copy is enough to fully replicate the object.
I need to compare an object just to check if it contains exactly the same values as another.
My ideas:
The first and most obvious solution is just to create a huge method block that compares each property, one after the other.
The second would be to serialize each object and hash the file or do some sort of md5 checksum on it. (Would this actually work?)
The third is to do some sort of reflection on the object, which would automate the first option, but create an added level of complexity.
Speed isn't really an issue.
I'm interested to hear thoughts, or any other methods I am missing to do such a thing.
Edit:
Thanks all. My solution (Modified to now be recursive on generic items):
public static bool IsSame<T>(T objA, T objB)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var pi in properties.Where(a => a.CanRead))
{
if (pi.Name == "Item")
{
var piCount = properties.FirstOrDefault(a => a.Name == "Count");
int count = -1;
if (piCount != null && piCount.PropertyType == typeof(System.Int32))
count = (int)piCount.GetValue(objA, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
dynamic child1 = pi.GetValue(objA, new object[] { i });
dynamic child2 = pi.GetValue(objB, new object[] { i });
return IsSame(child1, child2);
}
}
}
else
{
var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
return false;
}
}
return true;
}
Most serializers are designed to ensure that data retains its integrity during serialization and deserialization, not to produce a consistent serialized format. I would avoid using serialization for this purpose.
You may consider implementing IEquatable, to have each instance capable of comparing itself with instances of the same type. Or a class do do the comparisons for you that implements IEqualityComparer. How they do this comparison may be the 'big method' that compares properties one after the other, or uses reflection.
Reflection can be a fairly quick and simple way to achieve your goal but can cause problems down the line (for example if someone adds a property to your type that should not be included for comparing equality), but obviously the converse is also true (someone adds a property that should be checked for equality, but the equality comparison isn't updated). Which approach you use should generally be decided by how comfortable the team is with each approach in tandem with the context in which the class will be used.
In your case I'd probably recommend using the reflection based approach since you wish to check the result of a shallow clone operation, so all properties should be equal.
As an aside, I'd recommend using the MemberwiseClone method to create the clone, which would lessen the need for such stringent tests.
The third option (reflection) would be the slowest, but it would also be the most robust/testable.
The hash code would be very similar to the first option, since you would have to call all of your member variables, so 1 and 2 would require you to update your .Equals(obj) and .GenerateHash() methods every time you modify your member variable lists.
Here is some code to get you started:
foreach (FieldInfo field in this.GetType().GetFields())
{
if (o[field.Name] == null)
{
if (!field.GetValue(this).Equals(o[field.Name]))
return false;
}
else
{
return false;
}
}
return true;
Another thought is that if the properties return simple value types you could group them into immutable value types of their own. For instance, if you have a customer with properties string Address1 string Address2 string City string State string Zip, you could create a value type Address that implements its own equality comparer and use that.
Not sure if this applies to your situation, but I've found that when I have a class with a lot of properties, it is often possible to do this, and it tends to make my classes simpler and easier to reason about.
If you serialize you have to specify the serialization order on each Field/Property to ensure that all data is serialized int the same order. But all you would achieve is to implement GetHashCode() in an external class.
GetHashCode() has some examples on how to override it, so look there first.
If your class has a lot of fields, and you don't want to write all the code by hand. You could use reflection to autogenerate the code. If your class changes from time to time then you could create a partial class with the GetHashCode() implementation in a T4 template.