Compare c# Complex objects - c#

I am wondering about the best approach to the below
I have a .NET Web application and I am changing the ORM provider I am using. To do this I have created a new solution and removed the previous ORM and implemented my new one. As there are lots of existing screens that work with the previous ORM I want to make sure that the same object is returned by both ORMS. As these are in two separate VS slns is there a simple way I can compare the complex objects that all the same properties have been loaded on to the object graph. I could set a breakpoint and compare them manually but I don't really want to do this?

If this is for testing purposes, you can use FluentAssertions to check this.
The following code declares two unrelated types, ClassA and ClassB which contain two nested classes both called A and B but of different types.
Therefore the containing classes and the nested classes are of unrelated types, but the names of the members are the same, and for the nested classes the types of the properties are the same.
You can use FluentAssertions to test if the two instances classA and classB are equivalent - even though they are of different types - as follows:
using System;
using FluentAssertions;
namespace Demo
{
class ClassA
{
public NestedClassA A;
public NestedClassB B;
}
class NestedClassA
{
public string S;
public int I;
}
class NestedClassB
{
public char C;
public double D;
}
class ClassB
{
public NestedClassC A;
public NestedClassD B;
}
class NestedClassC
{
public string S;
public int I;
}
class NestedClassD
{
public char C;
public double D;
}
internal class Program
{
private static void Main()
{
var nestedA = new NestedClassA {I = 1, S = "1"};
var nestedB = new NestedClassB {C = '1', D = 1};
var nestedC = new NestedClassC { I = 1, S = "1" };
var nestedD = new NestedClassD { C = '1', D = 1 };
var classA = new ClassA {A = nestedA, B = nestedB};
var classB = new ClassB {A = nestedC, B = nestedD};
classA.ShouldBeEquivalentTo(classB); // Passes
classB.ShouldBeEquivalentTo(classA); // Passes
classB.B.D = 2; // Now the two objects do not contain equivalent data.
classA.ShouldBeEquivalentTo(classB); // Fails.
}
}
}

So I am guessing it is not as simple as to implement the IEquatable interface and directly compare your instances using this. You have to be aware that implementing proper comparing methods will be the fastest way.
But there are slower, more flexible ways. I think what you want to do is:
Compare two objects of unknown types
Check if they contain class variables with the same name
Check if the class variables have matching types
Check if the values in the variables are the same
There is only one way to do that. And it is to throw System.Reflection at the problem. Mind that this solution will be considerably slower then all solutions that work with known types.
So you need your ComplexEquals function.
public static bool ComplexEquals(object obj1, object obj2)
{
if (obj1 == null && obj2 == null) return true;
if (obj1 == null || obj2 == null) return false;
var obj1Class = obj1.GetType();
var obj2Class = obj2.GetType();
/* Get the instance fields (all of them) of both classes. */
var obj1Fields = obj1Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var obj2Fields = obj2Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var checkedFields = new HashSet<String>();
foreach (var obj1Field in obj1Fields)
{
var fieldName = obj1Field.Name;
checkedFields.Add(fieldName);
var obj2Field = obj2Fields.Where(f => f.Name == fieldName).SingleOrDefault();
if (obj2Field == null) return false;
if (obj1Field.FieldType == obj2Field.FieldType && !(obj1Field.GetValue(obj1).Equals(obj2Field.GetValue(obj2)))) return false;
}
if (obj2Fields.Any(f => !checkedFields.Contains(f.Name))) return false;
return true;
}
This is a simple version that relies on the Equals function starting at the first level inside the unknown function. This may be sufficient or not. But I think that is a starting point that can be extended if required.

Related

Perform a 'task' via an enum and a field, by checking the 'T' type, and inferring it into the task automatically

I've come across an issue that I cannot solve. I've got an IReadOnlyList of classes that each have a bunch of fields. These fields have names (variable names) identical to a list of enums. Think that for each field that exists, an enum for it with the exact same name also exists (so object helloHi has an equivalent enum something { helloHi }).
What I've attempted to do is compare the two field names. If they are identical, perform a function on them. The problem is that the function needs to infer a T from the variable, and since reflection isn't able to pull that 'T' without some form of cast, it won't proceed.
This is the code:
public class Something() {
[BackgroundTask]
private void load(Overlay param_1, Config param_2) {
Children = new Drawable[] // is the IReadOnlyList
{
SomethingClass(param_1),
AnotherClass(param_2)
}
performTask(this, param_2);
}
}
public class Config {
public void task<U>(SomeEnums se, ValueType<U> value) // do the task
}
public class SomethingClass {
ValueType<double> someDouble = new ValueType<double>();
ValueType<int> someInt = new ValueType<int>();
public SomethingClass(Overlay overlay) //...
}
public enum SomeEnums {
someDouble,
someInt,
}
void performTask(Something the_class, Config the_config) {
// ... for each field within the_class, do (uses reflection)
field => {
foreach (SomeEnums enums in Enum.GetValues(typeof(SomeEnums)))
{
if (field.Name == enums.ToString()) {
the_config.task(enums, field.GetValue(null)); // cant infer 'U' from an 'object'
}
}
}
}
Technically, I could just do the config.task within the class where the types are known and visible, but I'd much prefer to automate it from here, so that it doesn't need 2-3 changes every time a new variable is created.
One of the strategies I am aware of is performing an if check within the performTask like such:
// performTask, field =>, foreach
{
if (field.FieldType == ValueType<double>)
config.task(enums, (ValueType<double>)field.GetValue(null));
} //etc
However, I don't like this method. It would just need to introduce more and more checks if I ever created more ValueType<> and if they aren't already being checked for. Would there be a better way to perform what I want?
As I mentioned in my comment, I can't quite tell what you really want to do. However, here's some code that should help you figure it out.
It uses reflection to get the fields of objects, look at the names of those fields (comparing them to the values/names associated with an enum type) and compare the values. I do a comparison to integer 5, but you could compare to anything (but, it appears that the integer type's implementation of IComparable.CompareTo throws if it's compared to something other than an int, so I check). Since you know the type of everything, this is easy to check (you don't have to compare to a fixed Type, you can use what is returned by GetType()).
I started with some auxiliary types:
public enum SomeEnums {
SomeDouble,
SomeInt,
}
public class Class1 {
public int SomeInt = 5;
public double SomeDouble = 3.14;
}
public class Class2 {
public int SomeInt = 5;
public double SomeDouble = 6.28;
}
and then added this:
public class EnumFields {
public List<object> Objects = new List<object> {
new Class1(),
new Class2(),
};
public void PerformTask () {
var enumVals = Enum.GetNames(typeof(SomeEnums));
foreach (var obj in Objects) {
var objType = obj.GetType();
var fieldInfos = objType.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
//right around here I get lost. You have a list of objects (which has two instances right now),
//What are you comparing, that every field named SomeInt has the same value??
//Anyway, here's some code that should help you
foreach (var fieldInfo in fieldInfos) {
if (enumVals.Contains(fieldInfo.Name)) {
var fieldObj = fieldInfo.GetValue(obj);
var isSame = false;
if (fieldObj.GetType() == typeof(int)) {
var comparable = (IComparable)fieldObj;
var same = comparable.CompareTo(5);
isSame = (same == 0);
}
Debug.WriteLine($"Field: {fieldInfo.Name} of instance of {obj.GetType().Name} (Value: {fieldObj}) is equal to 5:{isSame}");
}
}
}
}
}
When I instantiate an EnumFields object and call PerformTask on it, I see this in the output:
Field: SomeInt of instance of Class1 (Value: 5) is equal to 5:True
Field: SomeDouble of instance of Class1 (Value: 3.14) is equal to 5:False
Field: SomeInt of instance of Class2 (Value: 5) is equal to 5:True
Field: SomeDouble of instance of Class2 (Value: 6.28) is equal to 5:False
This should get you most of the way there. I realize it doesn't answer your question. Had I been able to figure out what you were asking, it probably would have.

Intersect doesn't work between Lists

I have a little strange problem. I use Visual Studio and I am developing a project with C#.
I have two custom classes "Attr" and "FD" and I use lists that includes their objects e.g.
List<Attr> attrList = new List<Attr>();
List<FD> fdList = new List<FD>();
So when I try to find the intersection of two lists the result is not what I expect. To make it more simple I tried to Intersect similar Objects and the result is wrong again. What is going wrong?
This is the fd. It is an object of class FD.
This is the ff which is also an object of FD class.
As you can see these object contains exactly the same values.
The method GetLeft() returns a list that contains objects of class Attr.
So when I try to find the intersection between those two lists (fd.GetLeft() and ff.GetLeft() ) the result is nothing (it should be a list that contains an Attr object "A").
What did I miss?
P.S. These screenshots are from the debugg mode in Visual Studio.
In order to use Intersect I suggest implementing IEqualityComparer<T>, something like this :
public class FD
{
public string Name { get; set; }
}
static void Main()
{
List<FD> fdList1 = new List<FD>();
fdList1.Add(new FD { Name = "a" });
List<FD> fdList2 = new List<FD>();
fdList2.Add(new FD { Name = "a" });
IEnumerable<FD> fd = fdList1.Intersect<FD>(fdList2, new ComparerFd()).ToList();
}
And the CamparerFd should be like this :
public class ComparerFd : IEqualityComparer<FD>
{
public bool Equals(FD x, FD y)
{
return x.Name == y.Name;
}
public int GetHashCode(FD obj)
{
if(obj == null) return 0;
return obj.Name.GetHashCode();//Or whatever way to get hash code
}
}
If you created your own class, and did not override the Equals-method in that class, the Intersect-method will only compare the references of the objects, and not the properties.
Take the following, really simple class:
class MyClass
{
int Value { get; set; }
public MyClass(int value)
{
this.Value = value;
}
}
Now, create two lists, with both containing one object. The properties of the objects are the same, but the instances are not:
var list1 = new List<MyClass>
{
new MyClass(5)
};
var list2 = new List<MyClass>
{
new MyClass(5)
};
So the following will happen:
list1[0].Equals(list2[0]); // false
list1.Intersect(list2); // No matches
If you want these methods to compare the properties of your MyClass-objects, implement IEqualityComparer<MyClass>, e.g. change the classes signature to:
class MyClass : IEqualityComparer<MyClass>
{
..
}
Alternatively, you can just override Equals and GetHashCode, as then these methods will be called as default IEqualityComparer.
See the this answer on how to properly override Equals and GetHashCode.

Can't access generic property of child class when declaring super class

I might be currently confused, but I have the following problem.
I'm using C# but the point is more general, but I'm new to C# coming from Java.
I have a common abstract super class and multiple children.
Some children have generic properties which I can't access when I'm instantiating the a variable when declaring the common super type:
abstract class A
{
public string Prop0;
}
// Here every ok when instantiated
class B: A
{
public string Prop1;
}
// This makes trouble
class C<T> : A
{
public T Prop2;
}
Now I have a method which returns some subtype of A:
public A DoIt()
{
A a;
a = new C<string>();
a.Prop2; // <-- Can't access
}
(In my concrete case, the type can't be static because the child classes are serialized and have different shapes (C is a template with a property allowing anything). Still the question is general)
Why is this an issue and which solution is "correct" (except of using "object")
If a is always going to be set to a new instance of a C, then simply declare it as such:
public A DoIt()
{
C<string> c;
c = new C<string>();
var prop2 = c.Prop2;
return c;
}
But if you won't know if it's a C or not until it gets deserialized -- which it sounds from your explanation is the case here -- then here's a way to get that property if in fact it is a C (or get null if it's not a C):
public A DoIt()
{
A a;
a = new C<string>();
var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
return a;
}
Basically what this second approach does is check to see if a is an instance of C, and if so, it casts a to C and then reads its Prop2 property.
FOLLOW-UP EXAMPLE:
Here's code from an actual working console app that does something similar to what you've described. It's not a realistic scenario, and it may not be even close what you had in mind, but I'll post it anyway in case it gives you any ideas.
Note that this requires a reference to Json.NET (for the using Newtonsoft.Json; statement below).
using System;
using Newtonsoft.Json;
...
static void Main(string[] args)
{
var c = new C<string>() { Prop0 = "zero", Prop2 = "two" };
var json = JsonConvert.SerializeObject(c);
var prop2 = GetProp2(json);
Console.WriteLine("prop2 from C: " + (prop2 ?? "null"));
var b = new B() { Prop0 = "zero", Prop1 = "one" };
json = JsonConvert.SerializeObject(b);
prop2 = GetProp2(json);
Console.WriteLine("prop2 from B: " + (prop2 ?? "null"));
Console.Write("Press any key to exit...");
Console.ReadKey();
}
static object GetProp2(string json)
{
A a = JsonConvert.DeserializeObject<C<string>>(json);
var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
return prop2;
}
Results in the following output:
prop2 from C: two
prop2 from B: null
Press any key to exit...
Potential answer to question in comment: "How do you declare that some subtype of Shape shall be returned/instantiated".
If you want to specifically return C<T> results you can specify it as return type:
public C<TResult> DoIt<TResult>()
{
C<TResult> a;
a = new C<TResult>();
a.Prop2; // <-- Can access
return a;
}

Set property if exists in another list

I have two lists of type Derp:
public class Derp
{
public bool Valid;
public int SomeValue;
public int MoreValues;
public int EvenMoreValues;
public int ThereAreManyValues;
}
List<Derp> a = new List<Derp>();
List<Derp> b = new List<Derp>();
/// Populate both
var c = a.Intersect(b).Select(x=> { x.Valid = true; return x; });
I need to set Valid to true if b exists in a and keep all values in a. I can understand that the snippet above only keeps the intersected objects, but I need to retain a.
I've tried other funny things too (var c = a.Where(x => b.Contains(x)).Sel...) but I don't think I understand the List methods enough to solve this one.
Try this:
b.ForEach(x => {if (a.Contains(x)) {x.Valid = true;} });
The above works. However, do take note of #SriramSakthivel's comments and reconsider your approach if possible.
Demo

How to cast an instance of these similar classes?

I have two Classes that derive from a mutual class A, which contains some properties (mainly stings and integers). Class B is a different class containing additional properties. More precisely,
public class A1 : A {
private B _bee;
public B Bee {
get { return _bee;}
set { _bee = value;}
}
}
public class A2 : A {
private List<B> _beeList;
public List<B> BeeList {
get { return _beeList;}
set { _beeList = value;}
}
}
Now, given an instance of A1, how can I make an instance of A2 containing the same information (i.e., the properties in the 'A' part, and the instance of 'B'). I tried the following - I wished it'd work, but knew it wouldn't... - (Let me call my instance of A1 resp. A2 by 'one' resp. 'two'):
A _a = (A)one; // This obv works
B _b = one.Bee;
A2 _a2 = (A2)_a; // Threw away the Bee - information, so should work imo
_a2.BeeList.Add(_b);
So how do I do this without populating all properties in A by hand?
using System.Reflection;
private void Convert(A1 _a1, A2 _a2)
{
foreach(PropertyInfo pi in typeof(A).GetProperties())
{
pi.SetValue(_a2,
pi.GetValue(_a1, null)
, null);
}
_a2.BeeList.Add(_a1.Bee);
}
this seemed to work for me
try using automapper.
automapper enables you to copy properties of a class to another class without writing much code.
ex:
Mapper.CreateMap<X, Y>();
Y y = Mapper.Map<X, Y>(x);
Automapper configuration would look like this:
Mapper.CreateMap<A1, A2>()
.ForMember(a2 => a2.BeeList, ctx => ctx.MapFrom(a1 => new List<B>{a1.Bee}));
A a1Object = new A1{Bee = new B()};
A2 a2Object = Mapper.Map<A2>(a1Object);

Categories