Can I tell FluentAssertions to ignore Equals method when using BeEquivalentTo - c#

I have a simple class with two properties and the Equals method overridden:
public class Person : IEquatable<Person>
{
public Guid Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public bool Equals(Person other)
{
return other != null &&
this.Id.Equals(other.Id);
}
public override int GetHashCode()
{
return 2108858624 + EqualityComparer<Guid>.Default.GetHashCode(this.Id);
}
}
Now I created a simple test, where the Id values are the same, but the Name values are different.
[Fact]
public void PersonShouldNotBeEqual()
{
var guid = Guid.NewGuid();
var p1 = new Person { Id = guid, Name = "Me" };
var p2 = new Person { Id = guid, Name = "You" };
p1.Should().NotBeEquivalentTo(p2); // Fails
}
I understood from the documentation that BeEquivalentTo() uses the Equals() method by default when it is overridden in the class, but I haven't found a way to overrule that so the instances are compared by their property values.
Is it possible to do this in FluentAssertions other then the way below?
[Fact]
public void PersonShouldBeEqual()
{
var guid = Guid.NewGuid();
var p1 = new Person { Id = guid, Name = "Me" };
var p2 = new Person { Id = guid, Name = "You" };
p1.Id.Should().Be(p2.Id);
p1.Name.Should().Be(p2.Name);
}

You just need to override equality comparer for your type in EquivalencyAssertionOptions like this :
p1.Should().BeEquivalentTo(p2, options => options.ComparingByMembers<Person>())

You can also use dynamic objects.
[Fact]
public void PersonShouldNotBeEqual()
{
var guid = Guid.NewGuid();
var p1 = new Person { Id = guid, Name = "Me" };
dynamic p2 = new { Id = guid, Name = "You" };
p1.Should().NotBeEquivalentTo(p2);
dynamic p3 = new { Id = guid, Name = "Me" };
p1.Should().BeEquivalentTo(p3);
}
If you also need nested object comparison, use dynamic for them too.
dynamic expected = new
{
Id = 123,
Name = "John Doe",
City = new {
Id = 456,
Name = "Paris"
Country = new {
Id = 789,
Name = France
}
}
};

Related

How can i get the name of property and value from object and pass this name and value to a list in c#

I want to get the property name and the value from object and pass them to the list.
i dont want to pass one by one property and value to the list like commented in my code. want to use loop and add name and value dynamically
public class ParametersList
{
public string Name { get; set; }
public dynamic Value { get; set; }
}
public class BookVM
{
public string AuthorName{ get; set; }
public string CoverUrl { get; set; }
public int AuthorIds { get; set; }
}
public List<Book> Addgetallbooks(BookVM BookVM)
{
List<ParametersList> obj = new List<ParametersList>();
//List<ParametersList> obj = new List<ParametersList>
//{
// new ParametersList{Name=nameof(BookVM.AuthorIds),Value=BookVM.AuthorIds},
// new ParametersList{Name=nameof(BookVM.AuthorName),Value=BookVM.AuthorName},
// new ParametersList{Name=nameof(BookVM.CoverUrl),Value=BookVM.CoverUrl}
//};
var getdata = _opr.GetBooks1(obj);
return getdata;
}
You need to use reflection, but not sure if you should do it :)
[TestMethod]
public void Foo()
{
var book = new BookVM() { AuthorIds = 1, AuthorName = "some name", CoverUrl = "some cover url" };
var result = GetParameters(book);
result.Should().BeEquivalentTo(new[]
{
new ParametersList { Name = nameof(BookVM.AuthorIds), Value = 1 },
new ParametersList() { Name = nameof(BookVM.AuthorName), Value = "some name" },
new ParametersList { Name = nameof(BookVM.CoverUrl), Value = "some cover url" }
});
}
private static List<ParametersList> GetParameters(BookVM book)
{
return typeof(BookVM).GetProperties().Select(p => new ParametersList
{
Name = p.Name, Value = p.GetValue(book)
}).ToList();
}

With httpPut to skip that column if .net core is null or null

I am developing micro-service with .NET Core.
The following code is working with an HttpPut request.
But if any field has empty or null value in our incoming JSON request, I want it to retrieve the previous value.
I don't want to constantly run the code below. Is there a short way around this?
if(updateCustomer.Surname != null && updateCustomer.Surname !=string.Empty)
{
customer.Surname = updateCustomer.Surname;
}
var serviceResponse = new ServiceResponse<GetCustomerDto>();
Customer customer = await _context.Customers.FirstOrDefaultAsync(c => c.Id == updateCustomer.Id);
var persons = (from p in _context.Customers where p.Id == updateCustomer.Id select p);
foreach (var person in persons)
{
person.Name = updateCustomer.Name;
person.Surname = updateCustomer.Surname;
person.BusinessCode = "123";
person.Phone = updateCustomer.Phone;
}
await _context.SaveChangesAsync();
serviceResponse.Data = _mapper.Map<GetCustomerDto>(customer);
Following the GetValueOrDefault() idiom from Nullable types, you can create a string extension method to select between two values like so:
public static class StringExtensions
{
public static string GetValueOrDefault(this string str, string alternative)
{
if(string.IsNullOrEmpty(str))
{
return alternative;
}
return str;
}
}
public class Program
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string BusinessCode { get; set; }
public string Phone { get; set; }
}
public static void Main()
{
Person previous = new Person
{
Name = null,
Surname = "Smith",
BusinessCode = "123",
Phone = "(555) 123-4567"
};
Person current = new Person
{
Name = "John",
Surname = string.Empty,
BusinessCode = "321",
Phone = "(555) 765-4321"
};
Person updated = new Person
{
Name = current.Name.GetValueOrDefault(previous.Name),
Surname = current.Surname.GetValueOrDefault(previous.Surname),
BusinessCode = current.BusinessCode.GetValueOrDefault(previous.BusinessCode),
Phone = current.Phone.GetValueOrDefault(previous.Phone)
};
}
}

How to not serialize an object based on a property's value?

If the tags didn't give it away, I'm working with C#'s XmlSerializer class.
Say, for example, I have a Person class with various properties including age (int), name (string), and deceased (bool). Is there a way to specify that I don't want to serialize any objects whose deceased flags are true?
Edit: I should have specified, but unfortunately due to the situation I can't really edit my list of objects because it's a member of another class, which is what I'm actually serializing. Are there any other suggestions?
Assuming that you have following type of Class structure(As you specified in the comment)
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public bool Deceased { get; set; }
}
public class Being
{
public string Data { get; set; }
[XmlElement("Human")]
public Person Human { get; set; }
public bool ShouldSerializeHuman()
{
return !this.Human.Deceased;
}
}
Here I have added a method called ShouldSerialize this is called a pattern for XML serialization. Here you can use XmlArray and XmlArrayItem for lists etc.(With given name) then the ShouldSerialize checks if it can be serialized.
Below is the code I used for testing.
private static void Main(string[] args)
{
var livingHuman = new Person() { Age = 1, Name = "John Doe", Deceased = true };
var deadHuman = new Person() { Age = 1, Name = "John Doe", Deceased = false };
XmlSerializer serializer = new XmlSerializer(typeof(Being));
serializer.Serialize(Console.Out, new Being { Human = livingHuman, Data = "new" });
serializer.Serialize(Console.Out, new Being { Human = deadHuman, Data = "old" });
}
And here's the output:
=============================
Update:
If you have list of Person as Humans:
public class Being
{
// [XmlAttribute]
public string Data { get; set; }
// Here add the following attributes to the property
[XmlArray("Humans")]
[XmlArrayItem("Human")]
public List<Person> Humans { get; set; }
public bool ShouldSerializeHumans()
{
this.Humans = this.Humans.Where(x => !x.Deceased).ToList();
return true;
}
}
Sample Test:
private static void Main(string[] args)
{
var livingHuman = new Person() { Age = 1, Name = "John Doe", Deceased = true };
var deadHuman = new Person() { Age = 1, Name = "John Doe", Deceased = false };
var humans = new List<Person> { livingHuman, deadHuman };
XmlSerializer serializer = new XmlSerializer(typeof(Being));
serializer.Serialize(Console.Out, new Being() { Humans = humans, Data = "some other data" });
}
Output:
If you have a list of Person objects and only want to serialise some of them, then just filter out the ones you don't need. For example:
List<Person> people = GetPeople(); //from somewhere
List<Person> filteredPeople = people.Where(p => !p.Deceased);
Now you only need to serialise filteredPeople.

Cleanest Way To Map Entity To DTO With Linq Select?

I've been trying to come up with a clean and reusable way to map entities to their DTOs. Here is an example of what I've come up with and where I'm stuck.
Entities
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
// Other properties not included in DTO
}
public class Address
{
public int ID { get; set; }
public string City { get; set; }
// Other properties not included in DTO
}
DTOs
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
}
public class AddressDTO
{
public int ID { get; set; }
public string City { get; set; }
}
Expressions
This is how I began to handle the mapping. I wanted a solution that wouldn't execute the query before mapping. I've been told that if you pass a Func<in, out> instead of Expression<Func<in, out>> that it will execute the query before mapping.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = new AddressDTO()
{
ID = person.Address.ID,
City = person.Address.City
}
}
}
One issue with this is that I already have an expression that maps an Address to an AddressDTO so I have duplicated code. This will also break if person.Address is null. This gets messy very quick especially if I want to display other entities related to person in this same DTO. It becomes a birds nest of nested mappings.
I've tried the following but Linq doesn't know how to handle it.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = Convert(person.Address)
}
public static AddressDTO Convert(Address source)
{
if (source == null) return null;
return new AddressDTO()
{
ID = source.ID,
City = source.City
}
}
}
Are there any elegant solutions that I'm missing?
If you want to create mappings manually then you can use Select on the collection in the following way:
Some test data:
var persons = new List<Person>
{
new Person() {ID = 1, Name = "name1", Address = new Address() {ID = 1, City = "city1"}},
new Person() {ID = 2, Name = "name2", Address = new Address() {ID = 2, City = "city2"}},
new Person() {ID = 3, Name = "name3", Address = new Address() {ID = 1, City = "city1"}}
};
Mapping methods:
public static PersonDTO ToPersonDTOMap(Person person)
{
return new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = ToAddressDTOMap(person.Address)
};
}
public static AddressDTO ToAddressDTOMap(Address address)
{
return new AddressDTO()
{
ID = address.ID,
City = address.City
};
}
Actual usage:
var personsDTO = persons.Select(x => ToPersonDTOMap(x)).ToList();
Keep in mind that if this was a real query is would not get executed as long as it was IQueryable, it would be executed once you materialize it (using ToList() for example).
However, I would consider using some framework which could do it (the mappings) for you automatically (if your mapping are as simple as provided example(.
Just use AutoMapper.
Example:
Mapper.CreateMap<Address, AddressDTO>();
Mapper.CreateMap<Person, PersonDTO>();
Your query will execute when the mapping is performed but if there are fields in the entity that you're not interested use Project().To<> which is available both for NHibernate and EntityFramework. It will effectively do a select on the fields specified in the mapping configurations.
Automapper is the best way .
For me, I use this for simple objects only, but I don't recommend it
public static class ObjectMapper
{
public static T Map<T>(object objfrom, T objto)
{
var ToProperties = objto.GetType().GetProperties();
var FromProperties = objfrom.GetType().GetProperties();
ToProperties.ToList().ForEach(o =>
{
var fromp = FromProperties.FirstOrDefault(x => x.Name == o.Name && x.PropertyType == o.PropertyType);
if (fromp != null)
{
o.SetValue(objto, fromp.GetValue(objfrom));
}
});
return objto;
}
}
And I call it like that wherever I want
var myDTO= ObjectMapper.Map(MyObject, new MyObjectDTO());
You could either use AutoMapper or write extension methods like these:
public static class PersonMapper
{
public static PersonDTO ConvertToDTO(this Person person)
{
return new PersonDTO { ID = person.ID, Name = person.Name, Address = person.Address.ConvertToDTO() };
}
public static IEnumerable<PersonDTO> ConvertToDTO(this IEnumerable<Person> people)
{
return people.Select(person => person.ConvertToDTO());
}
}
public static class AddressMapper
{
public static AddressDTO ConvertToDTO(this Address address)
{
return new AddressDTO { ID = address.ID, City = address.City };
}
public static IEnumerable<AddressDTO> ConvertToDTO(this IEnumerable<Address> addresses)
{
return addresses.Select(address => address.ConvertToDTO());
}
}
You could then map a Person object to a PersonDTO object like this:
public class Program
{
static void Main(string[] args)
{
Person person = new Person { ID = 1, Name = "John", Address = new Address { ID = 1, City = "New Jersey" } };
PersonDTO personDTO = person.ConvertToDTO();
Console.WriteLine(personDTO.Name);
}
}
I see the way you want to do it. I can propose you this solution:
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
public static Expression<Func<Entities.Person, PersonDTO>> PersonSelector
{
get
{
return person => new PersonDTO()
{
ID = x.Id,
Name = x.Name,
Address = x.Address
.Select(AddressDTO.AddressSelector)
};
}
}
}
public async Task<PersonDTO> GetPerson(int id)
{
var person = await _personRepository.Get(id, PersonDTO.PersonSelector);
return person;
}
public async Task<TResult> Get<TResult>(int id, Expression<Func<Person, TResult>> selector)
{
var result = await _context.Persons
.Where(x => x.Id == id)
.Select(selector)
.SingleOrDefaultAsync();
return result;
}

Updating a Child Object by Assigning a New Object to Child Instance

This should be a fundamental C# question. Suppose I have a Person class which contains a property named Pets which is a List<Pet>.
If I want to update a pet, I can get the pet as a variable and manipulate properties on it, but I can't seem to create a new pet object and assign it to the existing pet object. I get a "Value assigned is not used in any execution path" warning. I created some very simple code that outlines this issue.
In my real code, I want to be able to use a new child object and replace and existing object. If you can show me how I can do that with the sample updatedCat below, I would greatly appreciate it!
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.RunMe();
}
public void RunMe()
{
var myPerson = new Person() { Name = "John Doe" };
var dog = new Pet() { Type = "Dog", Name = "Woofie" };
var cat = new Pet() { Type = "Cat", Name = "Chester" };
myPerson.Pets.Add(dog);
myPerson.Pets.Add(cat);
Console.WriteLine("Initial Pet Status:");
ListPets(myPerson);
var currentDog = myPerson.Pets.SingleOrDefault(p => p.Type == "Dog");
currentDog.Name = "Snoopie";
Console.WriteLine("\r\nPet Status After Updating Dog Directly (name should be 'Snoopie'):");
ListPets(myPerson);
var updatedCat = new Pet() { Type = "Cat", Name = "Felix" };
var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat");
currentCat = updatedCat;
//Resharper shows "Value assigned is not used in any execution path" for the currentCat
//and the current cat is never updated
Console.WriteLine("\r\nPet Status After Trying to Update Cat by Assigning a New Cat to existing Cat (name should be 'Felix' but it's not):");
ListPets(myPerson);
Console.ReadLine();
}
public void ListPets(Person person)
{
foreach (var pet in person.Pets)
{
Console.WriteLine(string.Format(" {0} has a {1} named {2}", person.Name, pet.Type, pet.Name));
}
}
}
public class Person
{
public string Name { get; set; }
public List<Pet> Pets { get; set; }
public Person()
{
Pets = new List<Pet>();
}
}
public class Pet
{
public string Type { get; set; }
public string Name { get; set; }
}
Edit to add Id value to Pet and create a InsertOrUpdatePet method
(Note: I removed the Console.Writeline command for succinctness)
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.RunMe();
}
public void RunMe()
{
var myPerson = new Person() { Name = "John Doe" };
var dog = new Pet() { Id = 1, Type = "Dog", Name = "Woofie" };
var cat = new Pet() { Id = 2, Type = "Cat", Name = "Chester" };
myPerson.Pets.Add(dog);
myPerson.Pets.Add(cat);
var updatedCat = new Pet() { Id = 2, Type = "Cat", Name = "Felix" };
InsertOrUpdatePet(myPerson, updatedCat);
var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat");
}
public void InsertOrUpdatePet(Person person, Pet pet)
{
var currentPet = person.Pets.SingleOrDefault(p => p.Id == pet.Id);
if(currentPet == null)
{
person.Pets.Add(pet);
}
else
{
currentPet = pet; // This doesn't work
person.Pets.SingleOrDefault(p => p.Id == pet.Id) = pet; //This throws an error
}
}
}
public class Person
{
public string Name { get; set; }
public List<Pet> Pets { get; set; }
public Person()
{
Pets = new List<Pet>();
}
}
public class Pet
{
public int Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
}
That depends on what do you want to do conceptually. If you want to say that the person got rid of the old cat and has now a new cat, you should do that: remove the old cat and then the new cat:
var updatedCat = new Pet() { Type = "Cat", Name = "Felix" };
var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat");
myPerson.Remove(currentCat);
myPerson.Add(updatedCat);
If, on the other hand, the person still has the same cat, but the cat was renamed, you should rename the old cat, the same way you did it with the dog:
var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat");
currentCat.Name = "Felix";
Your code doesn't work, because currentCat is something that references the cat, not the spot in the list. If you want some way to represent the spot in the list, you could use indexing into the list, as Jason suggested.
You'll need to Remove the pet you want to replace and Add a new Pet.
Alteratively, you can say
person.Pets[index] = new Pet() { Type = "Cat", Name = "Felix" };
where index is the index of the Pet that you want to replace.
What you're not understanding is that a List of Pet is merely a list of references to Pet instances.
Getting a reference to one of these Pet instances and storing it in a variable and assigning a reference to a new instance of Pet does not change where any of the references in the List refer to. Of course not, you haven't modified the list in anyway. That's why you either have to remove the element you want to replace, and add a new element, or directly assign a reference to a new instance to the element that you want to replace.

Categories