SequenceEqual different results - c#

in the code below calling SequenceEqual on generic list return true (as expected) when List is defined with class generic type (EquatableClass.Equals<> is called).
If list is defined with IEquatable interface, Equals method is not called and result is false (object.Equals is called instead, not in code).
The question is, why the EquatableClass.Equals<> method is not called in the second case?
public class EquatableClass : IEquatable<EquatableClass>
{
public string Name { get; set; }
public bool Equals(EquatableClass other) => this.Name.Equals(other.Name);
}
static void Main(string[] args)
{
var A = new List<EquatableClass> { new EquatableClass { Name = "A" } };
var B = new List<EquatableClass> { new EquatableClass { Name = "A" } };
var result1 = A.SequenceEqual(B); // == true;
var AA = new List<IEquatable<EquatableClass>> { new EquatableClass { Name = "A" } };
var BB = new List<IEquatable<EquatableClass>> { new EquatableClass { Name = "A" } };
var result2 = AA.SequenceEqual(BB); // == false;
}

The SequenceEqual<T> method will try to see if it can convert T to IEquatable<T>, and if it can, it will use IEquatable<T>.Equals for equality.
When you have a List<EquatableClass> it will then try to convert EquatableClass to IEquatable<EquatableClass>, and that succeeds, so it uses the appropriate Equals method.
When you have a List<IEquatable<EquatableClass>> it will then try to convert IEquatable<EquatableClass> to IEquatable<IEquatable<EquatableClass>>, and that will fail, because the actual object doesn't implement IEquatable<IEquatable<EquatableClass>>, so it resorts to the default behavior of using object.Equals(object), which you don't override.

Related

How do I print values in c# subarray?

I am new to c# and I am trying to print a user defined structure. Code:
var tracksArr = new[]
{new
{ vessel = GetVesselInfo(aisRecord.VesselId),
points = new[]
{ new
{ stampUtc = aisRecord.Time.ToString("yyyy-MM-ddTHH:mm:ssZ"),
}}}}
foreach (var item in tracksArr)
{Console.WriteLine("qqq: " + item.ToString());}
which prints:
qqq: { vessel = { key = 123456,0, mmsi = 7891011, imo = 0 }, points =
<>f__AnonymousType18`6[System.String,System.Double,System.Double...
what is this mysterious <>f__AnonymousType18 and how do I get the value of points?
For each anonymous type with unique set of fields (the new { ... } statements in means creation of instance of anonymous type) compiler will generate a class, which name will look like <>f__AnonymousType18. This class has overridden ToString method, but arrays/collections - don't and point is an array, so by default ToString returns type name which is YourAnonymousTypeName[] for arrays. You can use string.Join to output your collection:
Console.WriteLine($"qqq: {{vessel = {item.vessel}, points = {string.Join(", ", item.points.Select(p => p.ToString()))}}}");
Or create/use another collection type for points which will have overridden ToString method which returns string with all elements:
public static class ext
{
public static MyList<T> ToMyList<T>(this T[] arr)
{
return new MyList<T>(arr);
}
}
public class MyList<T> : List<T>
{
public MyList(T[] arr)
{
AddRange(arr);
}
public override string ToString()
{
return string.Join(",", this);
}
}
var tracksArr = new[]
{new
{ vessel = 1,
points = new[]
{ new
{ stampUtc = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ"), }
}
.ToMyList()
}
}; // prints "qqq: { vessel = 1, points = { stampUtc = 2020-06-24T14:58:08Z } }"

How to get the value of a property from a function which returns an object?

I have this function which returns an object:
private object function1()
{
return new
{
string1 = "a",
string2 = "b"
}
}
I want to store 'string1' into a variable. How will I achieve this? Here's what I tried but it does not solve the problem:
var a = function1().string1;
Option 1 - Do it properly
In other words, don't use the other methods unless you really have to
You really shouldn't be returning anonymous types, the correct way to do this is make a proper class and return that instead. Otherwise you have to resort to reflection or dynamic types which is just hacky:
Class:
public class Foo
{
public string String1 { get; set; }
public string String1 { get; set; }
}
Method:
private Foo Function1()
{
return new Foo
{
String1 = "a",
String2 = "b"
}
}
Usage:
var a = Function1().String1; // Though it's worth checking for a null return in production code
Option 2 - Use reflection
In other words, please don't do this
Using your code above, you can use reflection to get the property and call it manually, for example:
var result = function1();
var property = result.GetType().GetProperty("string1");
var a = (string)property.GetValue(result);
Option 3 - Use dynamic typing
In other words, pretty please with sugar on top, don't do this!
Cast the return to dynamic and you can call any method/property you like, but this is not type safe and will throw a runtime exception if you call a non-existent method.
var result = (dynamic)function1();
var a = (string)result.string1;
I would strongly suggest to use a proper class definition instead of returning an anonymous type
class MyClass {
string string1 {get;set;}
string string2 {get;set;}
}
private MyClass function1() {
return new MyClass {
string1 = "a", string2 = "b"
};
}
Console.WriteLine(function1().string1);
If you really want to use anonymous types you will have to use reflection. Be aware, there is no errorhandling in the code below. You will have to check, wheter the property exists, and has the correct type!
public class Program
{
public static object f1() {
return new {string1 = "a", string2 = "b"};
}
public static void Main()
{
var x = f1();
var p = x.GetType().GetProperty("string1");
string s = (string)p.GetValue(x);
Console.WriteLine(s);
}
}
You can create a new class to do it in stead of return a new object:
public class TestClass
{
public string str1{set;get;}
public string str2{set;get;}
}
Example:
private TestClass function1()
{
return new TestClass()
{
str1 = "a",
str2 = "b"
}
}
Usage:
var a = function1().str1;
As others have stated, the proper way of doing it is creating a class to return the result.
However, as of C# 7 there is another option called tuple deconstruction (note: you need at least a C# 7 compiler like the one in Visual Studio 2017 for this to work):
private (string, string) Function1()
{
return ("a", "b");
}
// In your calling method:
(string left, string right) = Function1();
System.Console.WriteLine($"left = {left}, right = {right}.");

C# ObservableCollection.IndexOf(...) returns -1

I wrote this code to check a Collection to find objects with the same value, but it returns the index -1 and causes an IndexOutOfRangeException. Can anyone help find my mistake?
List<MyFileInfo> selectedItemsList = dataInbox.SelectedItems.Cast<MyFileInfo>().ToList();
foreach (MyFileInfo file in selectedItemsList)
{
if (!file.AdditionalColumn.Equals(""))
{
inDB = new ZeichnungInDB(file.FileInfo.Name, file.AdditionalColumn, file.AdditionalColumn2, file.FileInfo.Extension,
txtAenderungExtern.Text, file.AdditionalColumn3,
int.Parse(txtProjectNumber.Text), txtTag.Text, bemerkung, anhangPfad, cmbDokumententyp.Text, false);
if (zeichnungCollection.Count > 0)
{
if (zeichnungCollection[zeichnungCollection.IndexOf(inDB)].Zeichnungsnummer != inDB.Zeichnungsnummer &&
zeichnungCollection[zeichnungCollection.IndexOf(inDB)].Extension != inDB.Extension)
{
zeichnungCollection.Add(inDB);
}
else
{
sameData = true;
}
}
else
{
zeichnungCollection.Add(inDB);
}
}
}
You are creating a new instance of an object, you are then attempting to find the Index of that object where your collection actually holds reference to a different instance.
You can use FindIndex with ToList to pass in a predicate and find the index of the object where a condition is true.
https://msdn.microsoft.com/en-us/library/x1xzf2ca(v=vs.110).aspx
Alternatively, you could use FirstOrDefault with some null checking if you'd prefer to keep it as an ObservableCollection
https://msdn.microsoft.com/en-us/library/bb340482(v=vs.110).aspx
Assume MyFileInfo looks like this:
public class MyFileInfo
{
public string Name { get; set; }
}
Now try to use it like this:
List<MyFileInfo> selectedItemsList = new List<MyFileInfo>
{
new MyFileInfo { Name = "One" },
new MyFileInfo { Name = "Two" },
};
MyFileInfo two = new MyFileInfo { Name = "Two" };
int index = selectedItemsList.IndexOf(two); // index == -1
IndexOf is looking for identical instance references, which it doesn't find, and so returns -1.
If you do this instead, though, the references are the same:
MyFileInfo two = new MyFileInfo { Name = "Two" };
List<MyFileInfo> selectedItemsList = new List<MyFileInfo>
{
new MyFileInfo { Name = "One" },
two,
};
int index = selectedItemsList.IndexOf(two); // index == 1
This is due to the default implementation of the Equals method, which just compares for reference equality. If you override Equals in MyFileInfo, you get to decide what Equals means. For example:
public class MyFileInfo
{
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj?.GetType() == typeof(MyFileInfo))
{
return ((MyFileInfo)obj).Name == Name;
}
return false;
}
}
This will find any object with the same Name.
Using methods with predicates is another option, which allows you to define what Equals means on the fly, e.g.:
List<MyFileInfo> selectedItemsList = new List<MyFileInfo>
{
new MyFileInfo { Name = "One" },
new MyFileInfo { Name = "Two" },
};
MyFileInfo two = new MyFileInfo { Name = "Two" };
int index = selectedItemsList.FindIndex(info => info.Name == two.Name);
Which also finds items with the same Name.
Note: If you override Equals in any class that might be used as a dictionary (hash table) key, you should also override GetHashCode. Here's a discussion. And there are considerations for implementing various other interfaces such as IEquatable<T>, especially for structs (value objects), which I guess is out of scope for this question.
Edit: Why it's important to override GetHashCode when overriding Equals

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

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

If chained - how to delete?

I'm doing an application where I have the following scenario:
I have several rules (business classes)
where they all return the client code. They are separate classes that will look for the code trial and error, if find the client code returns it and so on.
How can I use a rule without using a bunch of IFs or threaded IFs in the class that calls the others that contains the specific business rules?
For the specific classes, I used the design pattern strategy.
EX: Main Class
public abstract class Geral
{
public abstract string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada1 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica
return codigo;
}
}
public class derivada2 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 2
return codigo;
}
}
public class derivada3 : Geral
{
public override string retornaCodigo(Arquivo cliente)
{
var codigo = ""; // logica 3
return codigo ;
}
}
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivada1 = new derivada1().retornaCodigo(arquivo);
var derivada2 = new derivada2().retornaCodigo(arquivo);
var derivada3 = new derivada3().retornaCodigo(arquivo);
if (derivada1.Equals(null))
return derivada1;
if (derivada2.Equals(null))
return derivada2;
if (derivada3.Equals(null))
return derivada3;
return "";
}
}
what I wanted and that I did not have to use Ifs in the Business class for validation whether or not I found the code where it can fall under any condition gave example of 3 classes plus I have more than 15 conditions and can increase, case would be many Ifs.
Let's organize all derivada into a collection, say, array and then query the collection with a help of Linq
public string Codigo() {
var arquivo = new Arquivo();
Geral[] derivadas = new [] {
new derivada1(),
new derivada2(),
new derivada3();
};
//TODO: check the the condition: I guessed that you want to return first meanful codigo
foreach (var codigo in derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
If you have a lot of derivada you can try using Reflection in order to create a collection:
using System.Reflection;
...
private static Geral[] s_Derivadas = AppDomain
.CurrentDomain
.GetAssemblies() // scan assemblies
.SelectMany(asm => asm.GetTypes()) // types within them
.Where(t => !t.IsAbstract) // type is not abstract
.Where(t => typeof(Geral).IsAssignableFrom(t)) // type derived from Geral
.Where(t => t.GetConstructor(Type.EmptyTypes) != null) // has default constructor
.Select(t => Activator.CreateInstance(t) as Geral) // create type's instance
.ToArray(); // materialized as array
then
public string Codigo() {
var arquivo = new Arquivo();
foreach (var codigo in s_Derivadas.Select(geral => geral.retornaCodigo(arquivo)))
if (!string.IsNullOrEmpty(codigo))
return codigo;
return "";
}
You could create a list of derivada's and then iterate over it
and if any given derivada1 equals None, you simply return it, otherwise you just continue the 'for loop'
I could write up a snippet if this doesn't make sense to you. lmk!
This would be simple with Linq:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
return derivadaList.FirstOrDefault(d => d.retornaCodigo(arquivo) == null)?.retornaCodigo(arquivo) ?? "";
}
}
You can add as many Geral derived classes to the derivadaList as you want and the code will continue to function as designed.
What is happening here is that FirstOrDefault will run the Lamda expression on every element returning the first one that equals null (although I'm not sure this is what you want, it matches your example code). Since it returns a Geral object, you need to call retornaCodigo on it only if it is not null. If it is null, just return an empty string.
Another way to write this would be:
public class Negocio
{
public string Codigo()
{
var arquivo = new Arquivo();
var derivadaList = new List<Geral>() {
new derivada1(),
new derivada2(),
new derivada3(),
};
foreach (var derivada in derivadaList)
{
var result = derivada.retornaCodigo(arquivo);
if (result == null)
return result;
}
return "";
}
}
You can also use a list of derived classes and call them in Loop
public string Codigo()
{
var arquivo = new Arquivo();
List<Geral> gerals=new List<Geral>();
gerals.Add(new derivada1());
gerals.Add(new derivada2());
........
...........
foreach(Geral g in gerals)
{
var val=g.retornaCodigo(arquivo);
if(val!=null)
return val;
}
return "";
}
This is a sample implementation, However you are not using strategy correctly
A better approach will be constructor injection,
public string Codigo(Geral implementar)
{
var val=geral.retornaCodigo(arquivo);
return "";
}
Then instantiate only with the chosen strategy.
Otherwise if you want to chain multiple validations, then use CHain of responsibility pattern.

Categories

Resources