i have this certain Key in my Dictionary:
public class KKey
{
public string Name { get; set; }
public Guid Guid { get; set; }
}
Dictionary<KKey, string> myDictionary = new Dictionary<KKey, string>();
problem was everytime I generate new Guid, this condition wouldnt work:
if (false == myDictionary.TryGetValue(key, out keyobj))
because Guid key was new ...
Now my question was, how can i make condition that verify if Kkey.Name was already added, then dont add?
You either need to create a custom comparer or have your class override Equals and GetHashCode
Option 1: Comparer
sealed class NameEqualityComparer : IEqualityComparer<KKey>
{
public bool Equals(KKey x, KKey y)
{
return string.Equals(x.Name, y.Name);
}
public int GetHashCode(KKey obj)
{
return (obj.Name != null ? obj.Name.GetHashCode() : 0);
}
}
Dictionary<KKey, string> myDictionary = new Dictionary<KKey, string>(new NameEqualityComparer());
Option 2: Override
public class KKey : IEquatable<KKey>
{
public string Name { get; set; }
public Guid Guid { get; set; }
public bool Equals(KKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(Name, other.Name);
}
public override bool Equals(object obj)
{
return Equals(obj as KKey);
}
public override int GetHashCode()
{
return (Name != null ? Name.GetHashCode() : 0);
}
}
Dictionary<KKey, string> myDictionary = new Dictionary<KKey, string>();
can also be
bool alreadyAdded = keywordList.Any(n => n.Key.Name == name);
if (!alreadyAdded) { }
Related
i have trouble in adding duplicate element to a list
i want to add that object:
public class Allegato : BaseObject<Allegato, int>
{
public override int Id { get; set; }
public virtual string NomeFile { get; set; }
}
in BaseObject i implement equals looking only at Id Field
i cannot change this settings since those is need to my NHibernate Data Access Infrastracture
now i have other class with a list of Allegato objects
public class Corso : BaseObject<Corso, int>
{
public virtual ICollection<Allegato> Allegati { get; set; } = new List<Allegato>();
public virtual void AddAllegato(Allegato allegato)
{
this.Allegati.Add(allegato);
}
}
Now i need to add many Allegato to collection and then save it to database, ID will be empty since will be generate by DB sequence
using (myUow = myUowFactory.Create())
{
var obj = new Corso();
//populate corso
myUow.Corsi.Create(obj);
var files = SessionManagement.LeggiOggetto<SessionObject.File>(HttpContext, SessionManagement.ChiaveSessione.File);
foreach (var file in files)
obj.AddAllegato(new Allegato { NomeFile = file.Nome });
myUow.SaveAll();
}
first object is added but all other no. first element remain all others are not added
debugging it see that equals method of Allegato class is called, how can i avoid it?
thanks
EDIT
base object class
public abstract class BaseObject<TEntity, TKey> : EquatableObject<TEntity>
where TEntity : class
{
public abstract TKey Id { get; set; }
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
BaseObject<TEntity, TKey> other = obj as BaseObject<TEntity, TKey>;
return BaseObjectEquals(other);
}
public override bool Equals(TEntity obj)
{
if (obj == null)
return false;
BaseObject<TEntity, TKey> other = obj as BaseObject<TEntity, TKey>;
return BaseObjectEquals(other);
}
public virtual bool BaseObjectEquals(BaseObject<TEntity, TKey> other)
{
if (other == null)
return false;
return EqualityComparer<TKey>.Default.Equals(this.Id , other.Id);
}
private IEnumerable<FieldInfo> GetFields()
{
Type t = GetType();
List<FieldInfo> fields = new List<FieldInfo>();
while (t != typeof(object))
{
fields.AddRange(t.GetTypeInfo().DeclaredFields.Where(x => x.FieldType.Name != typeof(ICollection<>).Name));//.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public));
t = t.GetTypeInfo().BaseType;
}
return fields;
}
public static bool operator ==(BaseObject<TEntity, TKey> x, BaseObject<TEntity, TKey> y)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(x, y))
{
return true;
}
// If one is null, but not both, return false.
if (((object)x == null) || ((object)y == null))
{
return false;
}
return x.Equals(y);
}
public static bool operator !=(BaseObject<TEntity, TKey> x, BaseObject<TEntity, TKey> y)
{
return !(x == y);
}
}
as #Panagiotis Kanavos stated, problem is in NHibernate overwrite of my property with a Set collection. I changed the map to Bag to make it work
I am receiving KeyNotFoundException whenever I try to access the key in dictionary.
I have a PricingRules class which has a dictionary:
public class PricingRules
{
Dictionary<ItemCode, Money> pricing_rules;
public PricingRules()
{
pricing_rules = new Dictionary<ItemCode, Money>();
pricing_rules.Add(new ItemCode("A"), new Money(50));
pricing_rules.Add(new ItemCode("B"), new Money(30));
pricing_rules.Add(new ItemCode("C"), new Money(20));
pricing_rules.Add(new ItemCode("D"), new Money(15));
}
public void itemScanned(ItemCode itemCode, Money amount)
{
amount.Add(pricing_rules[itemCode]);
}
public Money AmountForItem(ItemCode itemCode)
{
return pricing_rules[itemCode];
}
}
The key in the dictionary is of type ItemCode:
public class ItemCode
{
private readonly string itemCode;
public ItemCode(string itemCode)
{
this.itemCode = itemCode;
}
public override int GetHashCode()
{
return itemCode.GetHashCode();
}
}
and the value is of type Money:
public class Money
{
private int amount;
public Money(int amount)
{
this.amount = amount;
}
public override bool Equals(object obj)
{
Money money = (Money)obj;
return this.amount == money.amount;
}
public void Add(object obj)
{
Money money = (Money)obj;
this.amount += money.amount;
}
public override int GetHashCode()
{
return amount.GetHashCode();
}
}
I have tried overriding the GetHashCode() function to return the HashCode of the primitive type in the class but it still is giving KeyNotFoundException
The test I have written is:
public class PricingRulesShould
{
[Fact]
void ReturnValueFiftyWhenKeyIsA()
{
Money expected = new Money(50);
PricingRules pr = new PricingRules();
ItemCode itemcode = new ItemCode("A");
Money actual = pr.AmountForItem(itemcode);
Assert.Equal(expected, actual);
}
}
When Dictionary accesses its elements, it looks for the equality of keys.
Since the ItemCode is not a primitive type, when you compare new ItemCode("A") == new ItemCode("A") you should get false as a result, because they are different instances with identical contents.
What you can do is to implement IEquatable<ItemCode> by the ItemCode class:
public class ItemCode : IEquatable<ItemCode>
{
private readonly string itemCode;
public ItemCode(string itemCode)
{
this.itemCode = itemCode;
}
public override int GetHashCode()
{
return itemCode != null ? itemCode.GetHashCode() : 0;
}
public bool Equals(ItemCode other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(itemCode, other.itemCode);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj is ItemCode ic && Equals(ic);
}
}
I have several classes with id property of the same type int?:
public class Person {
public int? id { get; set; }
}
public class Project {
public int? id { get; set; }
}
// etc...
When writing code it happened that I compared semantically wrong types:
if (person.id == project.id), and of course there was no warning until I found the bug.
How could I create some kind of underlying type enforcement, or even better, a compiler warning, or something like that, that warns me not everything looks o.k.?
I can think of creating an Equals(Person p) { return p.id == this.id } but I'd prefer some other mechanism that could be used more 'freely'.
You need to override Equals and GetHashCode to be able to compare objects directly.
Try like this:
public sealed class Person : IEquatable<Person>
{
private readonly int? _id;
public int? Id { get { return _id; } }
public Person(int? id)
{
_id = id;
}
public override bool Equals(object obj)
{
if (obj is Person)
return Equals((Person)obj);
return false;
}
public bool Equals(Person obj)
{
if (obj == null) return false;
if (!EqualityComparer<int?>.Default.Equals(_id, obj._id)) return false;
return true;
}
public override int GetHashCode()
{
int hash = 0;
hash ^= EqualityComparer<int?>.Default.GetHashCode(_id);
return hash;
}
public override string ToString()
{
return String.Format("{{ Id = {0} }}", _id);
}
public static bool operator ==(Person left, Person right)
{
if (object.ReferenceEquals(left, null))
{
return object.ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static bool operator !=(Person left, Person right)
{
return !(left == right);
}
}
public sealed class Project : IEquatable<Project>
{
private readonly int? _id;
public int? Id { get { return _id; } }
public Project(int? id)
{
_id = id;
}
public override bool Equals(object obj)
{
if (obj is Project)
return Equals((Project)obj);
return false;
}
public bool Equals(Project obj)
{
if (obj == null) return false;
if (!EqualityComparer<int?>.Default.Equals(_id, obj._id)) return false;
return true;
}
public override int GetHashCode()
{
int hash = 0;
hash ^= EqualityComparer<int?>.Default.GetHashCode(_id);
return hash;
}
public override string ToString()
{
return String.Format("{{ Id = {0} }}", _id);
}
public static bool operator ==(Project left, Project right)
{
if (object.ReferenceEquals(left, null))
{
return object.ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static bool operator !=(Project left, Project right)
{
return !(left == right);
}
}
I also implemented IEquatable<Person> and == and != for good measure.
Now you can write person1 == this if this is a Person, but you would have a compiler error if this were a Project.
This is what tests are for. This is why you should write tests. Tests should pick up on these kind of errors.
But if you really want to go overkill, create a custom struct to store your IDs:
public struct Id<T> {
public int? ID { get; }
public static implicit operator Id<T>(int id) {
return new Id<T>(id);
}
public Id(int? id) { ID = id; }
public static bool operator ==(Id<T> lhs, Id<T> rhs) {
return lhs.ID == rhs.ID;
}
public static bool operator !=(Id<T> lhs, Id<T> rhs) {
return lhs.ID != rhs.ID;
}
}
// usage:
public class Person {
public Id<Person> Id { get; set; }
}
public class Project {
public Id<Project> Id { get; set; }
}
Whenever you try to compare Person.Id with Project.Id, the compiler will give you an error because you are comparing Id<Project> and Id<Person>.
I have a simple class called User :
public class User
{
public int ID { get; set; }
public int MI { get; set; }
public User(int id, int mi)
{
ID = ID;
MI = mi;
}
}
And later on, I have a HashSet of Users that I want to get the ID's from and assign to a in HashSet as follows :
HashSet<Users> _users = new HashSet<>();
//code where several User objects are assigned to _users
HashSet<int> _usersIDs = new HashSet<int>();
_usersIDs = _users.Select("ID")
But this doesn't work, how can I successfully assigned all of the int ID's in _users to a new HashSet?
You can do:
HashSet<int> _usersIDs = new HashSet<int>(_users.Select(user=> user.ID));
But you should override GetHashCode for your User class if you are going to use it in a HashSet<T> and possibily Eqauls as well like:
public class User
{
protected bool Equals(User other)
{
return ID == other.ID && MI == other.MI;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((User) obj);
}
public override int GetHashCode()
{
unchecked
{
return (ID*397) ^ MI;
}
}
public int ID { get; set; }
public int MI { get; set; }
public User(int id, int mi)
{
ID = id; //based on #Jonesy comment
MI = mi;
}
}
here is the object code:
public class DlpItem : IEqualityComparer<DlpItem>
{
public string Text { get; set; }
public int Id { get; set; }
public DlpItem(int pId)
{
Text = string.Empty;
Id = pId;
}
public override bool Equals(object obj)
{
return Id == (obj as DlpItem).Id;
}
public bool Equals(DlpItem a, DlpItem b)
{
return a.Id == b.Id;
}
public int GetHashCode(DlpItem item)
{
return Id.GetHashCode();
}
}
And I have two lists as follows:
var list1 = new List<DlpItem>();
list1.Add(new DlpItem(1));
list1.Add(new DlpItem(2));
var list2 = new List<DlpItem>();
list2.Add(new DlpItem(1));
list2.Add(new DlpItem(2));
var delItems = list1.Except(list2).ToList<DlpItem>();
delItems always has both items in it. What am I missing here?
EDIT: Code now implements IEquatable
public class DlpItem : IEqualityComparer<DlpItem>, IEquatable<DlpItem>
{
public string Text { get; set; }
public int Id { get; set; }
public override bool Equals(object obj)
{
return Id - (obj as DlpItem).Id == 0;
}
public bool Equals(DlpItem a, DlpItem b)
{
return a.Id == b.Id;
}
public bool Equals(DlpItem item)
{
return item != null && Id == item.Id;
}
public int GetHashCode(DlpItem item)
{
return Id.GetHashCode();
}
}
In your example, you don't actually add anything to list2... a simple enough mistake, but there is a more significant issue:
It needs to be IEquatable<T> not an IEqualityComparer<T>; also, you might want to ensure the hashcode can't change; most simply by making Id read-only:
public class DlpItem : IEquatable<DlpItem>
{
public string Text { get; set; }
private readonly int id;
public int Id { get { return id; } }
public DlpItem(int id)
{
Text = "";
this.id = id;
}
public override bool Equals(object obj)
{
return Equals(obj as DlpItem);
}
public bool Equals(DlpItem other)
{
return other != null && this.Id == other.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}