Comparing two List<MyClass>: How to find out difference? - c#

I used to compare lists like this, but it returns false in a test:
Assert.IsTrue(expected.SequenceEquals(actual));
And tried converting to json and it worked:
Assert.AreEqual(expected.ToJson(), actual.ToJson());
Values seems to be equal, what could be different? How to find out what is different in the lists?
Updated:
My class:
public class Department
{
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Id.ToString();
}
}

If MyClass implements IEquatable<MyClass>, then try this:
expected.Sort();
actual.Sort();
if (Enumerable.SequenceEqual(actual, expected)) { ... }
If it does not implement IEquatable then you could expect strange behavior, since the object references will be compared in the two lists, and not their fields:
using System;
using System.Collections.Generic;
using System.Linq;
public class MyClassA
{
private int i;
public MyClassA(int i) { this.i = i; }
}
public class MyClassB : IEquatable<MyClassB>
{
private int i;
public MyClassB(int i) { this.i = i; }
public bool Equals(MyClassB other) { return this.i == other.i; }
}
public class Program
{
public static void Main()
{
var actual1 = new List<MyClassA>() { new MyClassA(1), new MyClassA(2), new MyClassA(3) };
var expected1 = new List<MyClassA>() { new MyClassA(1), new MyClassA(2), new MyClassA(3) };
Console.WriteLine(Enumerable.SequenceEqual(actual1, expected1));
var a1 = new MyClassA(1);
var a2 = new MyClassA(2);
var a3 = new MyClassA(3);
var actual2 = new List<MyClassA>() { a1, a2, a3 };
var expected2 = new List<MyClassA>() { a1, a2, a3 };
Console.WriteLine(Enumerable.SequenceEqual(actual2, expected2));
var actual3 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
var expected3 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
Console.WriteLine(Enumerable.SequenceEqual(actual3, expected3));
var actual4 = new List<MyClassB>() { new MyClassB(1), new MyClassB(2), new MyClassB(3) };
var expected4 = new List<MyClassB>() { new MyClassB(3), new MyClassB(2), new MyClassB(1) };
Console.WriteLine(Enumerable.SequenceEqual(actual4, expected4));
}
}
Output:
False
True
True
False

using System.Linq;
Enumerable.SequenceEqual(a, b);
// or SequenceEqual(a, b, StringComparer.OrdinalIgnoreCase)
See MSDN, also this question.

Perhaps you can use IEnumerable.ExceptOf
http://msdn.microsoft.com/en-us/library/bb300779.aspx
Our perhaps you can use an HashSet and there the intersect method.
http://msdn.microsoft.com/en-us/library/bb293080.aspx

I tend to find the HashSet<T> collection fit for this kind of purpose, cast your collections into HashSet<T> then call SetEquals

Related

A constructor that takes object from same type

So I want to create constructor for my class EmployeeNodeClass that takes In EmployeeNodeClass object and copies it using a deepclone funtion:
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
to the new object.
At first i thought that it is as simple as
public EmployeeNodeClass(EmployeeNodeClass EMPND)
{
this = DeepClone(EMPND);
}
but then I got the error that this is readonly.
so how can I do it?
It can be done using NewtonSoft JsonConvert.PopulateObject:
Example:
class Entity
{
public List<int> List { get; set; }
public Entity(List<int> list)
{
List = list;
}
public Entity(Entity original)
{
string originalJson = JsonConvert.SerializeObject(original);
JsonConvert.PopulateObject(originalJson, this);
}
}
And using it:
static void Main(string[] args)
{
var entity1 = new Entity(new List<int> { 1, 2, 3 });
var entity2 = new Entity(entity1);
entity1.List[0] = 5;
Console.WriteLine(entity2.List[0]);
}
Note: since this uses NewtonSoft Json, it will only clone public, writable properties. So internal state in private fields (that are not associated with such properties) will be lost.

Two classes but same object

I have 2 tables, tblA and tblB, with same fields and types. I get datas through linq to sql so I have 2 partial classes clsTblA and clsTblB.
I have a combo to choose tblA or tblB and I have to read in that table and do some query.
What I'am trying to do is evitate to duplicate code to run the same methods.
So now I have (in pseudo-code):
if (combo == "A")
{
List<clsTblA> listUserNow = ctx.clsTblA.Where(p => p.blabla).ToList();
List<clsTblA> listUserLastYear = ctx.clsTblA.Where(q => q.blabla).ToList();
}
if (combo == "B")
{
List<clsTblB> listUserNow = ctx.clsTblB.Where(p => p.blabla).ToList();
List<clsTblB> listUserLastYear = ctx.clsTblB.Where(q => q.blabla).ToList();
}
But I have in mind something like this (in pseudo-code):
SupClsTable clsTblX = null;
if (combo == A)
clsTblX = new clsTblA();
if (combo == B)
clsTblX = new clsTblB();
List<clsTblX> listUserNow = tblX.QueryForNow();
List<clsTblX> listUserLastYear = tblX.QueryForLastYear();
Does it exist something like this?
I also searched in design pattern but without results.
Thanks in advance.
EDIT 1:
At this moment the code is like:
if (combo == A)
{
using (DbDataContext ctx = new DbDataContext())
{
List<clsTblA> listUserNow = ctx.clsTblA.Where(p => p.blabla).ToList();
List<clsTblA> listUserLastYear = ctx.clsTblA.Where(q => q.blabla).ToList();
}
}
if (combo == B)
{
using (DbDataContext ctx = new DbDataContext())
{
List<clsTblB> listUserNow = ctx.clsTblB.Where(p => p.blabla).ToList();
List<clsTblB> listUserLastYear = ctx.clsTblB.Where(q => q.blabla).ToList();
}
}
so I have twice listUserNow and listUserLastYear.
How can I let me return a unique
using (DbDataContext ctx = new DbDataContext())
{
List<*something*> listUserNow = ctx.*something*.Where(p => p.blabla).ToList();
List<*something*> listUserLastYear = ctx.*something*.Where(p => p.blabla).ToList();
}
indipendent from "if combo"?
Thanks in advence
It seems like what you're looking for are Interfaces. i.e.
interface ISampleInterface
{
void SampleMethod();
}
class ImplementationClass : ISampleInterface
{
// Explicit interface member implementation:
void ISampleInterface.SampleMethod()
{
// Method implementation.
}
}
You can learn more about that on the Microsoft documentation site Microsoft Docs
EDIT: To clearify. Once both Classes inerhit from the Interface you could write the following
if (combo == A)
clsTblX = new clsTblA();
if (combo == B)
clsTblX = new clsTblB();
as follows
IClsTable clsTbl = (combo == A)? new ClsTblA() : new ClsTblB() // example
and work with the clsTbl like you would've previously with ClsTblA or ClsTblB since both follow the same structure and have same properties and methods.
Maybe this dotnetfiddle example helps you understand the concept of this solution.
While personally I think interfacing is better option for your use case, you could also implement something like this that will make it easy for you to extend. Same can be casted against interface as well. So every time a new combo is added just add a case and it extends easily.
public class ComboFactory
{
public static SuperCombo GetComboClassInstance(string comboCode)
{
switch(comboCode)
{
case "A":
return new ComboA();
case "B":
return new ComboB();
//and so on
}
}
}
Try to see if this is what you need:
public interface iTbl
{
int Property1 { get; set; }
string Property2 { get; set; }
void WhatAreYou();
}
public class clsTblA : iTbl
{
public int Property1 { get; set; }
public string Property2 { get; set; }
public void WhatAreYou()
{
Console.WriteLine("I am a clsTblA!");
}
}
public class clsTblB : iTbl
{
public int Property1 { get; set; }
public string Property2 { get; set; }
public void WhatAreYou()
{
Console.WriteLine("I am a clsTblB!");
}
}
public class Program
{
public static void Main()
{
List<iTbl> tbls = new List<iTbl>()
{
new clsTblA(),
new clsTblB(),
new clsTblB(),
new clsTblA(),
new clsTblA()
};
foreach (var tbl in tbls)
{
tbl.WhatAreYou();
}
}
}
Output:
I am a clsTblA!
I am a clsTblB!
I am a clsTblB!
I am a clsTblA!
I am a clsTblA!

How to add multiple values to list C#

Hi I have the following code when I am adding values to a list.
var NoLiftingList = new List<SQLFields>();
SQLFields nolifting = new SQLFields();
nolifting.Field1 = "No lifting";
NoLiftingList.Add(nolifting);
SQLFields extremelifting = new SQLFields();
extremelifting.Field1 = "Up to 100 lbs (extreme lifting)";
NoLiftingList.Add(extremelifting);
How can I simplify this? Instead of initializing a new object all the time.
This is the code for the whole class updated below.
Thanks
You can add to a list, and set properties on a class by using this inline constructor syntax (working example):
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var NoLiftingList = new List<SQLFields>
{
new SQLFields
{
Field1 = "No Lifting"
},
new SQLFields
{
Field1 = "Up to 100lbs (extreme lifting)"
}
};
}
}
public class SQLFields
{
public string Field1 { get; set; }
}
Use Object Initializers with anonymous types
var NoLiftingList = new List<SQLFields>(){
new SQLFields() { Field1 = "No lifting"},
new SQLFields() { Field1 = "Up to 100 lbs (extreme lifting)"}
};
Ref: MSDN Link
Try this
var NoLiftingList = new List<SQLFields>()
{
new SQLFields()
{
Field1 = "No lifting"
},
new SQLFields()
{
Field1 = "Up to 100 lbs (extreme lifting)"
}
};

Replace object on heap?

Maybe this is real simple or breaking all the rules or maybe I just dont know what its called so I cant find it.
Anyway, I want to be able to replace an entire object on the heap. I've added a small code sample to show what I want to do, and a way of doing it, but I just want to know if there is a more elegant way?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BasicObjectTest
{
class Program
{
static void Main(string[] args)
{
List<Test> testList = new List<Test>
{
new Test {Value=1,NiceString="First" },
new Test {Value=2,NiceString="Second" },
new Test {Value=3,NiceString="Third" }
};
var replacementTestClass = new Test { Value = 2, NiceString = "NEW" };
EasyWay(testList, replacementTestClass);
var correctTestClass = testList.FirstOrDefault(x => x.Value == 2);
Console.WriteLine(correctTestClass.NiceString); //Expecting "Forth"
Console.ReadLine();
HardWay(testList, replacementTestClass);
correctTestClass = testList.FirstOrDefault(x => x.Value == 2);
Console.WriteLine(correctTestClass.NiceString);
Console.ReadLine();
}
private static void HardWay(List<Test> testList, Test replacementTestClass)
{
//This will work!
var secondTestClass = testList.FirstOrDefault(x => x.Value == 2);
CopyPropertiesUsingPropertyInfo(secondTestClass, replacementTestClass);
}
private static void CopyPropertiesUsingPropertyInfo(Test secondTestClass, Test replacementTestClass)
{
foreach(var pi in secondTestClass.GetType().GetProperties())
{
pi.SetValue(secondTestClass, pi.GetValue(replacementTestClass, null));
}
}
private static void EasyWay(List<Test> testList, Test replacementTestClass)
{
//This wont work, but I want it to!
var secondTestClass = testList.FirstOrDefault(x => x.Value == 2);
secondTestClass = replacementTestClass;
}
}
}
and my Test object
class Test
{
public int Value { get; set; }
public string NiceString { get; set; }
}
There must be a more elegant way of doing this?
I know why the first alternative does not work: I just change the object reference for that variable.
Update:
Using this thinking I understood it for a long time I tested this now thinking it would work, but the test fails. Why? Didnt I replace the object so that every object using it should use the new object? See complete code below
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var main = new Main { Property = 1 };
var dependent = new Dependent(main);
void ChangeRef(ref Main Oldmain, Main newMain)
{
Oldmain = newMain;
}
ChangeRef(ref main, new Main { Property = 5 });
Assert.AreEqual(5,dependent.Main.Property);
}
}
public class Main
{
public int Property { get; set; }
}
public class Dependent
{
public Dependent(Main main)
{
Main = main;
}
public Main Main { get; set; }
}
There must be a more elegant way of doing this?
There is one basic thing you're missing. When you search for the object in the list, and one is found, you get back a copy of the reference pointing to that object. This means that when you alter it, you're only altering the copy. The original reference in the list is still pointing to that same old object instance.
but what if I didnt have a list. I just had the object reference in a
variable?
Then you could use the ref keyword to pass the reference type by reference:
public static void Main(string[] args)
{
var test = new Test { Value = 1, NiceString = "First" };
var newTest = new Test { Value = 2, NiceString = "AlteredTest!" };
UpdateTest(ref test, newTest);
Console.WriteLine(test.NiceString); // "AlteredTest!"
}
public static void UpdateTest(ref Test originalTest, Test other)
{
originalTest = other;
}
An alternative way to approach this is with the proverbial "extra level of indirection".
Instead of storing the objects in the list, you store wrapper objects instead. The wrapper object provides an "Item" field which points to the actual object. Then you can update the "Item" field to point it at the new object.
A simple generic wrapper class could look like this:
class Wrapper<T>
{
public T Item;
public Wrapper(T item)
{
Item = item;
}
public static implicit operator Wrapper<T>(T item)
{
return new Wrapper<T>(item);
}
}
Then you could use it like so:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Test
{
public int Value { get; set; }
public string NiceString { get; set; }
}
class Wrapper<T>
{
public T Item;
public Wrapper(T item)
{
Item = item;
}
public static implicit operator Wrapper<T>(T item)
{
return new Wrapper<T>(item);
}
}
class Program
{
static void Main(string[] args)
{
var testList = new List<Wrapper<Test>>
{
new Test {Value = 1, NiceString = "First"},
new Test {Value = 2, NiceString = "Second"},
new Test {Value = 3, NiceString = "Third"}
};
var replacementTestClass = new Test { Value = 2, NiceString = "NEW" };
EasyWay(testList, replacementTestClass);
var correctTestClass = testList.FirstOrDefault(x => x.Item.Value == 2);
Console.WriteLine(correctTestClass.Item.NiceString); //Expecting "New"
Console.ReadLine();
}
private static void EasyWay(List<Wrapper<Test>> testList, Test replacementTestClass)
{
var secondTestClass = testList.FirstOrDefault(x => x.Item.Value == 2);
secondTestClass.Item = replacementTestClass;
}
}
}

Using DefaultIfEmpty with an object?

I saw an example on MSDN where it would let you specify the default value if nothing is returned. See below:
List<int> months = new List<int> { };
int firstMonth2 = months.DefaultIfEmpty(1).First();
Is it possible to use this functionality with an object? Example:
class object
{
int id;
string name;
}
code:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(/*something to define object in here*/).name;
UPDATE:
I was thinking I could do something like this:
List<myObjec> objs = new List<myObjec> {};
string defaultName = objs.DefaultIfEmpty(new myObjec(-1,"test")).name;
But haven't been able to. It should be noted that I am actually trying to use this method on an object defined in my DBML using LINQ-To-SQL. Not sure if that makes a difference in this case or not.
You need to pass an instantiated class as a parameter of the DefaultIfEmpty.
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test() { i = 1, name = "testing" }).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
}
To add to it and make it a bit more elegant (IMO) add a default constructor:
class Program
{
static void Main(string[] args)
{
var lTest = new List<Test>();
var s = lTest.DefaultIfEmpty(new Test()).First().name;
Console.WriteLine(s);
Console.ReadLine();
}
}
public class Test
{
public int i { get; set; }
public string name { get; set; }
public Test() { i = 2; name = "testing2"; }
}
As per the MSDN page on this Extension Method you can do what you want:
http://msdn.microsoft.com/en-us/library/bb355419.aspx
Check the sample on this page for an example on how to use this with an object.
i must admit i am not too sure i understand your question, but i'll try to suggest using double question mark if the returned object might be null. Like so:
myList.FirstOrDefault() ?? new myObject();
You can create a default Object Like this:
Object o_Obj_Default = new Object();
o_Obj_Default.id = 3;
o_Obj_Default.name = "C";
And add it to your default value :
string defaultName = objs.DefaultIfEmpty(o_Obj_Default).First().name;
If your list "objs" is empty, the result will be "C"

Categories

Resources