Trying to check that my ObservableCollection doesn't have an object matching the one i'm trying to add.
For example:
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (UserList.Where(x => x == user))
{
UserList.Add(user);
}
}
}
So if the ObservableCollection has got a Logged object with the same property values as the Add(Logged user) then I want it to not add the user.
Edit 1:
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (!UserList.Any(x => x == user))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 2:
Changed my Logged class to the following:
namespace PhotoManagement
{
public class Logged : Common.NotifyUIBase
{
public string ClearPassword { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public long UID { get; set; }
public string Email { get; set; }
//Display basic statistics
public int ThisDayImageCount { get; set; }
public int ThisDaySaleCount { get; set; }
public Logged()
{
//Update the stats when instigated
UpdateStats();
}
//Update the stats
public void UpdateStats()
{
}
public bool Equals(Logged other)
{
if (other == null) return false;
return (this.UID.Equals(other.UID));
}
}
}
So this should work? However it still says Already Exists when I have checked the instances and they are different.
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (!UserList.Any(x => x.Equals(user)))
{
UserList.Add(user);
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
The best solution is to implement IEquatable as said #vadim-martynov.
Another fast but no so clean solution is to search by explicitly comparing values:
public void Add(Logged user)
{
if (!UserList.Any(x => x.Id == user.Id && x.UserName == user.UserName))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 1:
Think about your Logged class. The key here is to implement the IEquatable interface who implement Equals method. There should you implement the explicitly comparing you will apply then we call Equals on this class.
public class Logged: IEquatable<Logged>
{
public int Id { get; set; }
public string UserName { get; set; }
public string OtherProperty { get; set; }
public bool Equals(Logged other)
{
return this.Id == other.Id && this.UserName == other.UserName;
}
}
After you Add method will look like:
public void Add(Logged user)
{
if (!UserList.Any(x => x.Equals(user)))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 2:
Ok, then we must try a planb. Try implementing IComparable and try using with this. IEquatable should work but if not, this could work too.
public class Logged: IEquatable<Logged>, IComparable<Logged>
{
public int Id { get; set; }
public string UserName { get; set; }
public string OtherProperty { get; set; }
public bool Equals(Logged other)
{
return this.Id == other.Id && this.UserName == other.UserName;
}
public int CompareTo(Logged other)
{
return this.Id.CompareTo(other.Id);
}
}
IComparable returns int. So the usage and integer result are:
var result = x.CompareTo(user)
// Comparing 'some text' with '123': 1
// Comparing 'some text' with 'some text': 0
// Comparing 'some text' with 'Some Text': -1
Try to specify the attribute in the query to find match, ex. Username or User ID.
public void Add(Logged user)
{
if (!UserList.Any(u => u.Username == user.Username))
{
UserList.Add(user);
}
}
By default your object compared by reference via == operator. It's common feature of reference types in c#.
You can override this operator or override Equals method.
The new implementation of Equals should not throw exceptions. It is
recommended that any class that overrides Equals also override
System.Object.GetHashCode. It is also recommended that in addition to
implementing Equals(object), any class also implement Equals(type) for
their own type, to enhance performance.
Also, you can implement IEquatable<T> for your Logged class.
To avoid having different results depending on the way you check the
equality of the objects, you should override the Object.Equals method
in your class. This ensures that whenever a class doesn't use
the IEquatable.Equals method, still the same checks will be performed.
Finally you can compare some properties of 2 instances inside Where method:
if(!UserList.Any(u => u.Login == user.Login))
{
UserList.Add(user);
}
Related
I want to practice code with DRY principle, but my method uses 2 different classes, classOneDTO and classTwoDTO.. They have different properties and I want to linked it with PRIMARYIDENTIFIER prop with both have the same..
How can I create a generic method to get the property that I want to query with Linq.
Updated: my purpose is to have a generic method that will query the PrimaryIdentifier and get the data to it whether they are using classOneDTO or classTwoDTO. Is there a way to have a single generic method to do this?
private void genericMethod<T>(List<T> workList, GridView grid, int columnNo)
{
if (workList.Any())
{
string CodeString = default;
// Want to dynamic get the properties in different class with PrimaryIDentifier property
// want to check if PrimaryIdentifier is NULL OR EMPTY
var getDataOne = workList.Cast<classOneDTO>().FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
// causing error because of the CAST if wrong type request
var getDataTwo = workList.Cast<classTwoDTO>().FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getDataOne != null || getDataTwo != null)
{
CodeString = (getDataOne != null) ? getDataOne.PrimaryIdentifier : getDataTwo.PrimaryIdentifier;
}
}
}
public class classOneDTO
{
public int PatientID { get; set; }
public string PrimaryIdentifier { get; set; }
public string FirstName{ get; set; }
// so oonnn...
}
public class classTwoDTO
{
public int EntryID { get; set; }
public string PrimaryIdentifier { get; set; }
public string Location{ get; set; }
// so oonnn...
}
All that you need is to make both your classes implement the same interface, i.e. IDTO:
public interface IDTO
{
string PrimaryIdentifier { get; set; }
}
Then you can tell the compiler to accept only types that implement your new interface:
private void GenericMethod<DTO>(List<DTO> workList, GridView grid, int columnNo)
where DTO: IDTO
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
(Pay attention to the 2nd row)
Additionally, I also made minor adjustments to your class and method namings based on standard .Net naming convention.
Here's the full code:
public class Client
{
private void GenericMethod<DTO>(List<DTO> workList, GridView grid, int columnNo)
where DTO: IDTO
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
}
public class ClassOneDTO : IDTO
{
public int PatientID { get; set; }
public string PrimaryIdentifier { get; set; }
public string FirstName { get; set; }
// so oonnn...
}
public class ClassTwoDTO : IDTO
{
public int EntryID { get; set; }
public string PrimaryIdentifier { get; set; }
public string Location { get; set; }
// so oonnn...
}
public interface IDTO
{
string PrimaryIdentifier { get; set; }
}
EDIT: as Johnathan Barclay correctly pointed out, there's actually no need to have a generic method if you don't need some more advanced logic there that you didn't show in your example.
private void GenericMethod(IEnumerable<IDTO> workList, GridView grid, int columnNo)
{
if (workList.Any())
{
string CodeString = default;
var getData = workList.FirstOrDefault(x => !string.IsNullOrEmpty(x.PrimaryIdentifier));
if (getData != null)
{
CodeString = getData?.PrimaryIdentifier;
}
}
}
I have these two classes
enum CustomerType {
CitizenBank = 0,
Wellsfargo = 1
}
public abstarct class CustomerDto {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
public CitizenBank: CustomerDto {}
public Wellsfargo: CustomerDto {}
Public Class CustomerEntity {
int customerId {
get;
set;
}
string customerName {
get;
set;
}
string CustometAddress {
get;
set;
}
int CustomerTypeId {
get;
set;
}
}
I wrote a class to convert from entity to DTO
public class EntityModelToModel {
///Method to convert
public CustomerDto ToDto(CustomerEntity customerEntity) {
/// returns type customerDto based on customertypeid
switch (CustomerType) {
case Wellsfargo
return New Wellsfargo()
case citizen
return new citizen() //calls method that converts from customer Entity to citizen
}
}
I have method to check if my types match
public bool CanExecute(CustomerEntity customerEntity) {
foreach(var customerType in Enum.GetValues(typeof(Enums.customerType) if (customerEntity.CustomerType == customerType)
return true
else
false
}
}
Now my calling code I have array of CustomerEntity[] which have two items of customerid for wellsfargo and citizens. I want to do this
var res = CustomerEntity[].where(x => EntityModelToModel.CanExecute(x).Select(x => EntityModelToModel.ToDto(x))
My problem is:
If my array has two items this only checks the first items and returns.
What I want is it should check for two items and return them.
I think that you should change your CanExecute method like this:
public static class EntityModelToModel
{
// ...
public static bool CanExecute(CustomerEntity customerEntity)
{
foreach (var customerType in Enum.GetValues(typeof(CustomerType)))
{
if (customerEntity.CustomerTypeId == (int)customerType)
{
return true;
}
}
return false;
}
}
Because your method break execution flow after first check.
I have a lot of POCO classes that contain several virtual properties each. Something like this:
public class Policy
{
public int Id { get; set; }
public int EntityId { get; set; }
public int ProgramId { get; set; }
public string PolicyNumber { get; set; }
public DateTime EffectiveDate { get; set; }
public DateTime ExpirationDate { get; set; }
public virtual Entity Entity{ get; set; }
public virtual Program Program { get; set; }
public virtual ICollection<Transaction> Transactions { get; set; }
}
To make Dapper.Extensions work, I need to write a mapping for each of these classes, which is fine. My problem is, if there are any virtual properties inside a class, they need to be explicitly marked as ignored, which I always forget to do.
public sealed class PolicyMapper : BaseMapper<Policy>
{
public PolicyMapper()
{
Map(p => p.Entity).Ignore();
Map(p => p.Program).Ignore();
Map(p => p.Transactions).Ignore();
AutoMap();
}
}
What would be great for me, if the Dapper.Extensions library will automatically exclude virtual properties, if any, when mapped to the POCO class. There is an extension for Automapper that does something similar (link). Is there a way to do that for Dapper.Extensions library? Possibly something like this:
public sealed class PolicyMapper : BaseMapper<Policy>
{
public PolicyMapper()
{
IgnoreAllVirtual();
AutoMap();
}
}
I found my own solution. Since all my mapping classes derive from BaseMapper class, I decided to override AutoMap() method that will exclude virtual properties:
public class BaseMapper<T> : ClassMapper<T> where T : BaseClass
{
public BaseMapper()
{
}
protected override void AutoMap()
{
CustomAutoMap(null);
}
private void CustomAutoMap(Func<Type, PropertyInfo, bool> canMap)
{
Type type = typeof(T);
bool hasDefinedKey = Properties.Any(p => p.KeyType != KeyType.NotAKey);
PropertyMap keyMap = null;
foreach (var propertyInfo in type.GetProperties())
{
// Exclude virtual properties
if (propertyInfo.GetGetMethod().IsVirtual)
{
continue;
}
if (Properties.Any(p => p.Name.Equals(propertyInfo.Name, StringComparison.InvariantCultureIgnoreCase)))
{
continue;
}
if ((canMap != null && !canMap(type, propertyInfo)))
{
continue;
}
PropertyMap map = Map(propertyInfo);
if (!hasDefinedKey)
{
if (string.Equals(map.PropertyInfo.Name, "id", StringComparison.InvariantCultureIgnoreCase))
{
keyMap = map;
}
if (keyMap == null && map.PropertyInfo.Name.EndsWith("id", true, CultureInfo.InvariantCulture))
{
keyMap = map;
}
}
}
if (keyMap != null)
{
keyMap.Key(PropertyTypeKeyTypeMapping.ContainsKey(keyMap.PropertyInfo.PropertyType)
? PropertyTypeKeyTypeMapping[keyMap.PropertyInfo.PropertyType]
: KeyType.Assigned);
}
}
}
}
I have a list of custom class called List<Notifications>.
The class is below:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
}
Before adding an instance of the Notification class to my custom list, I want to check if it is already in the list.
What is the best way to achieve this?
You can use 1.) Contains, but then you have to override Equals (+ GethashCode).
bool contains = list.Contains(someNotificationInstance);
For example:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
public override bool Equals(object obj)
{
return obj is Notification && string.Equals(ID, ((Notification)obj).ID);
}
public override int GetHashCode()
{
return ID == null ? 0 : ID.GetHashCode();
}
}
2.) another option is to provide a custom IEqualityComparer<Notification> for Contains:
public class NotificationComparer : IEqualityComparer<Notification>
{
public bool Equals(Notification x, Notification y)
{
return x.ID == y.ID;
}
public int GetHashCode(Notification obj)
{
return obj.ID == null ? 0 : obj.ID.GetHashCode();
}
}
On this way you don't need to modify the original class. You can use it in this way:
bool contains = list.Contains(someInstance, new NotificationComparer());
3.) Probably the easiest approach is using Enumerable.Any:
bool contains = list.Any(n => someInstance.ID == n.ID);
4.) The most efficient approach is using a set if no duplicates are allowed in the collection anyway. Then you can use the first or second approaches for a HashSet<T>:
var set = new HashSet<Notification>(new NotificationComparer());
set.Add(instance1);
bool contains = !set.Add(instance2);
You can check it with Contains method.
if (!mylist.Select(l => l.ID).Contains(mynewid)) {
var item = new Notifcation();
item.ID = mynewid;
item..... // fill the rest
mylist.Add(item);
}
Maybe a better approch would be use of Dictionary.
I want to fetch the details of manager from manager class if at run time I give kinid of employee from the employee class. How can I do this using Equals or Hashcode?
public class employee
{
public string empname { get; set;}
public string location { get; set; }
public int kinid { get; set; }
public double magkin { get; set; }
}
public class manager
{
public string magname { get; set; }
public double magkin { get; set; }
}
Dictionary<employee, manager> relation = new Dictionary<employee, manager>();
I haven't used C# in a long time, but Something like this should work:
kinidFind is the kinid you want to search for.
manager findManager(int kinidFind) {
foreach( KeyValuePair<employee, manager> i in relation) {
if (i.Key.kinid==kinidFind) {
return i.Value;
}
}
}
Assuming that kinid is a unique identifier (you don't care about other fields of employee in identifying), then on employee class you could do the following:
override int GetHashCode()
{
return kinid;
}
override bool Equals(Object obj)
{
if (obj == null) return false;
emploee emp = obj as employee;
if ((System.Object)emp == null) return false;
return (kinid == emp.kinid);
}
However, this is not a good general solution because what if later on you want to find the employee by other fields?
Consider changing that dictionary to:
Dictionary<int,manager> where the int is the kinid of the employee then it's self explanatory.
or since the Dictionary has been loaded you can Enumerate it this way as well it's just a question of feel or taste at this point from Brads answer
foreach (var pair in relation)
{
if (pair.key == kinidFind )
{
return relation[pair.key];
}
}