C# How to override Dictionary ContainsKey [duplicate] - c#

This question already has answers here:
Dictionary.ContainsKey return False, but a want True
(12 answers)
Closed 2 years ago.
public class Date
{
public int mm;
public int dd;
public Date(int get_mm, int get_dd)
{
mm = get_mm;
dd = get_dd;
}
}
public Dictionary<Date, int> dictionary = new Dictionary<Date, int>();
Date A = new Date(1,1)
Date B = new Date(1,1)
dictionary.Add(A,1);
if(dictionary.ContainsKey(B)) //returns false
...
How do i override the Date class in this situation?
I know the 2 objects is not the same, but don't know how to make it work

You have 2 ways :
By overriding the GetHashCode and Equals method of you class Date.
By using the Dictionary constructor that accepts one IEqualityComparer<Key> as argument.
It is not recommended to use the first method if your Date object is not immutable (i.e. that its attributes can't be modified after its creation => Date attributes need to be readonly). Because the Dictionary class builds its internal structure based on GetHashCode value at insert time. If the attributes used to compute the GetHashCode change, you won't be able to retrieve your objects already inserted in the dictionary.

Related

Searching for key in a dictionary, when the key is an object. C# [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 months ago.
Improve this question
//Checking if there already exists a relationship
if (tree.ContainsKey(parent))
{
`//get the current children
temp = tree[parent];
//add the new child
temp = temp.Append(child).ToArray();
//overwrite the current children
tree[parent] = temp;
//create new record with null children
tree[child] = new Node[] { };`
}
The above code describes the process of checking if there already exists a key(parent) in he dictionary(tree). In this case the key is an object.
While debugging I noticed that it does not detected keys which already exist, yet I do not know the reason.
Below find attached two images - an image of the key which is already in the dictionary, an image of the key which is being checked.
Based on a comment above:
it does not override the Equals and GetHashCode methods
Then this assertion is false:
keys which already exist
Two objects are not the same just because their properties have the same values. Much in the same way that two people are not the same person just because they have the same name.
In the absence of any logic indicating otherwise, the default comparison for "sameness" for objects is reference equality. So unless the two references point to the same object in memory, they are not the same object.
You can provide custom comparison logic by overriding Equals and GetHashCode in your class. The Dictionary<> would then be able to use your logic to determine if two objects are "the same".
In this specific case I think maybe GetHashCode is the only one that's required of the two, but it's always a good idea to override both any time you want to implement "sameness". You might also implement IComparable, override ToString, etc.
A quick example to demonstrate, this should write the first Count to the console but throw an exception for the second Dictionary<> saying:
System.ArgumentException: An item with the same key has already been added.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// adds a second record
var notSameDict = new Dictionary<NotSame, int>();
notSameDict.Add(new NotSame { Foo = "test" }, 1);
notSameDict.Add(new NotSame { Foo = "test" }, 2);
Console.WriteLine(notSameDict.Count);
// does not add a second record
var sameDict = new Dictionary<Same, int>();
sameDict.Add(new Same { Foo = "test" }, 1);
sameDict.Add(new Same { Foo = "test" }, 2);
Console.WriteLine(sameDict.Count);
}
}
public class NotSame
{
public string Foo { get; set; }
}
public class Same
{
public string Foo { get; set; }
public override bool Equals(object obj)
{
return Foo.Equals((obj as Same).Foo);
}
public override int GetHashCode()
{
return Foo.GetHashCode();
}
}

Why does Equals method of attributes compare fields? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
When I checked the attributes for equality, I noticed that they already have Equals method that compares the fields. For custom classes this comparison does not occur, since it is bad for performance, but why was an exception made for attributes?
Here's the code to make sure:
public class MyAttribute : Attribute
{
public int Value { get; }
public MyAttribute(int value) => Value = value;
}
public class MyClass
{
public int Value { get; }
public MyClass(int value) => Value = value;
}
public class Test
{
[Test]
public void TestEquals()
{
var myAttributeLeft = new MyAttribute(1);
var myAttributeRight = new MyAttribute(1);
var attributeEqualityResult = myAttributeLeft.Equals(myAttributeRight);
Console.WriteLine(attributeEqualityResult); // true
var myClassLeft = new MyClass(1);
var myClassRight = new MyClass(1);
var classEqualityResult = myClassLeft.Equals(myClassRight);
Console.WriteLine(classEqualityResult); // false
}
}
Custom attributes are not intended for use as domain objects: they are explicitly intended to represent metadata that are hard-coded at compile time. Assuming they are used as intended, this gives them a few special properties:
There are limits on the types that they are allowed to use: typically native types like int and string, and arrays of those native types.
The number of items that could be put into an array on the type is bounded by the number of items that are written into an actual code file.
In domain models it could create enormous performance penalties to compare the values of fields, properties, and elements of collections: you don't know how big the object structure for a given class might be, and a collection could have millions of items in it. But the restrictions mentioned above mean that the cost of an equality comparison for custom attributes is pretty well bounded. Evidently the creators of .NET felt that this made it worthwhile to give the base class value semantics, although the documentation includes remarks that recommend overriding the default implementation to use object equality or hard-coded value semantics instead.
Short answer: System.Attribute implements its own implementation of Equals which is different from the one in System.Object (from which MyClass class inherits)
You can find a more detailed answer on ms docs

Sort a List based on a field in a class [duplicate]

This question already has answers here:
Sorting mixed numbers and strings
(10 answers)
Closed 3 years ago.
I created a class called tagNoMatchList that has fields tag, col, and msg.
public class tagErrorsClass
{
public string tag { get; set; }
public string col { get; set; }
public string msg { get; set; }
}
I created a List of tagNoMatchList as shown below.
var tagNoMatchList = new List<tagErrorsClass>();
Now want to sort the list on col. The code below sorts the list, but not the way that I want.
tagNoMatchList.Sort((x, y) => x.col.CompareTo(y.col));
If col contains "A29", "A21", "A52", "A16", and "A6", after sorting I get "A16", "A21", "A29", "A52", "A6". I want "A6" at the beginning of the list not at the end. Do I have to split the col string into letter (A) and number and sort each, or is there a built in comparison that will make this easier?
There is no built-in comparison for this. You will need to write code to handle the comparison.
However, there's not enough information yet in the question for us to provide this code for you, namely whether or not the col will always begin with A, or whether it could have other (or no) prefix values, and how that might impact the sorting.

Two dictionaries intersection C# [duplicate]

This question already has answers here:
Intersect with a custom IEqualityComparer using Linq
(2 answers)
C# Linq intersect/except with one part of object
(7 answers)
Closed 5 years ago.
I had two DateTime lists and was intersecting them with no problems:
IEnumerable<DateTime> both = list1.Intersect(list2);
I have the custom data type and still need to find the intersection:
public class AssetRecord
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public double AssetPrice { get; set; }
}
// Lits initialization
public static List<AssetRecord> list1 = new List<AssetRecord> { };
// Key/Values - Date/Price. Custom data type is used to store an object in the collection
public static List<AssetRecord> list2 = new List<AssetRecord> { };
The problem is that IEnumerable takes only DataTime lists as an input and I do not have that data type anymore. Is it possible to find intersection using custom types? Or is it possible to take only Date field from created data type and convert it to List and then pass it to IEnumerable?
The problem is that IEnumerable takes only DataTime lists
Huh? That makes no sense. IEnumerable<T> takes whatever T you choose. In this case IEnumerable<AssetRecord> will contain AssetRecords.
Now, that is not your main problem. Your issue is with how intersect works. Enumerable.Intersect<T> takes the default equality of T. So, what is the default equality comparer of AssetRecord? Reference equality, and you probably want value equality semantics.
Solution? Override Equals in AssetRecord accordingly and while your at it implement IEquatable<AssetRecord> too (and don't forget to override GetHashCode with a consistent behavior):
public class AssetRecord: //IEquatable<AssetRecord> left as exercise
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public decimal AssetPrice { get; set; }
public override bool Equals(object other)
{
if (other is AssetRecord)
{
var ass = (AssetRecord)other;
return ass.AssetDate == AssetDate &&
ass.AssetPrice == AssetPrice;
}
return false;
}
public override int GetHashCode()
{
return AssetDate.GetHashCode() ^ AssetPrice.GetHashCode();
}
}
If you can't touch AssetRecord then implement an IEqualityComparer<AssetRecord> and use the corresponding overload of Intersect.
Two more issues with your code worth mentioning:
Prices should be a decimal, not a double. You want exact decimal values, use the right tool provided by the framework.
Your type is already named AssetRecord, it should probably be named Asset, but anyway, there is no need to have properties with redundant information. Price and Date should be enough.

Why is this one line of code different than the two above it? [duplicate]

This question already has answers here:
Modify Struct variable in a Dictionary
(5 answers)
Closed 9 years ago.
See question in commented code...
public struct Key
{
public string Name;
public object Value;
}
public class PrimaryKey
{
Dictionary<string, Key> _keys = new Dictionary<string, Key>();
object this[string index]
{
get
{
return _keys[index].Value;
}
set
{
if (!_keys.ContainsKey(index))
_keys.Add(index, new Key() { Name = index, Value = value });
else
{
var k = _keys[index]; // This compiles
k.Value = value; // just fine.
_keys[index].Value = index; // So why wouldn't this?
}
}
}
}
I get the error:
Cannot modify the return value of Dictionary<string,Key>.this[string] because it is not a variable
Since Key is struct and struct is a value type, when you access it via a Method, Property or Indexer it returns a copy of the struct instance not the instance itself. Try declaring Key as class. For detailed information you can search for difrences between struct and class or value and reference types.
It is purely because of your Key being a struct. The value is copied out.. which means making changes won't actually do anything other than change your newly discarded copy. The compiler is stopping that from happening.
Changing it to a class will give you the functionality you're after.. but may not actually be what you wanted:
public class Key { }
Your first two lines does compile, but they doesn't work. To change the value stored in the dictionary you have to put the changed value back in the dictionary:
var k = _keys[index];
k.Value = value;
_keys [index] = k;
When you change the value that you get from the dictionary in the same statement, the compiler can notice that you are about to do something that doesn't make sense, but when you divide it into two statements the compiler can't protect you from yourself.
This kind of quirks is one of the reasons that it's recommended not to make structs mutable. With a class both your ways of changing the value works, and with an immutable struct you can't make such a mistake.

Categories