Take this example. Foo is overriden with new. This crashes TypeExtensions.FindProperty because it will see object Foo and string Foo
```c#
[TestMethod]
public void FluentAssertionsTest()
{
var a1 = new B<string> { Foo = "test" };
var a2 = new E<string> { Foo = "test" };
a1.ShouldBeEquivalentTo(a2);
//a1.ShouldBeEquivalentTo(a2, ex => ex.Using(new MustMatchByNameAndTypeRule()));
}
public class A
{
public object Foo { get; set; }
}
public class B<T> : A
{
public new T Foo
{
get
{
return (T)base.Foo;
}
set
{
base.Foo = value;
}
}
}
public class D
{
public object Foo { get; set; }
}
public class E<T> : D
{
public new T Foo
{
get
{
return (T)base.Foo;
}
set
{
base.Foo = value;
}
}
}
```
My suggestion is to add 2 new matchers:
```c#
public class MustMatchByNameAndTypeRule : IMatchingRule
{
public PropertyInfo Match(PropertyInfo subjectProperty, object expectation, string propertyPath)
{
PropertyInfo compareeProperty = expectation.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.SingleOrDefault(pi => pi.Name == subjectProperty.Name && pi.PropertyType == subjectProperty.PropertyType);
if (compareeProperty == null)
{
string path = (propertyPath.Length > 0) ? propertyPath + "." : "property ";
Execute.Verification.FailWith(
"Subject has " + path + subjectProperty.Name + " that the other object does not have.");
}
return compareeProperty;
}
public override string ToString()
{
return "Match property by name and type (or throw)";
}
}
public class TryMatchByNameAndTypeRule : IMatchingRule
{
public PropertyInfo Match(PropertyInfo subjectProperty, object expectation, string propertyPath)
{
PropertyInfo compareeProperty = expectation.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.SingleOrDefault(pi => pi.Name == subjectProperty.Name && pi.PropertyType == subjectProperty.PropertyType);
return compareeProperty;
}
public override string ToString()
{
return "Try to match property by name and type";
}
}
```
Comments: Fixed in commit https://fluentassertions.codeplex.com/SourceControl/changeset/3c0f594993f6c69e9e2c5c09d213edb44c771648
```c#
[TestMethod]
public void FluentAssertionsTest()
{
var a1 = new B<string> { Foo = "test" };
var a2 = new E<string> { Foo = "test" };
a1.ShouldBeEquivalentTo(a2);
//a1.ShouldBeEquivalentTo(a2, ex => ex.Using(new MustMatchByNameAndTypeRule()));
}
public class A
{
public object Foo { get; set; }
}
public class B<T> : A
{
public new T Foo
{
get
{
return (T)base.Foo;
}
set
{
base.Foo = value;
}
}
}
public class D
{
public object Foo { get; set; }
}
public class E<T> : D
{
public new T Foo
{
get
{
return (T)base.Foo;
}
set
{
base.Foo = value;
}
}
}
```
My suggestion is to add 2 new matchers:
```c#
public class MustMatchByNameAndTypeRule : IMatchingRule
{
public PropertyInfo Match(PropertyInfo subjectProperty, object expectation, string propertyPath)
{
PropertyInfo compareeProperty = expectation.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.SingleOrDefault(pi => pi.Name == subjectProperty.Name && pi.PropertyType == subjectProperty.PropertyType);
if (compareeProperty == null)
{
string path = (propertyPath.Length > 0) ? propertyPath + "." : "property ";
Execute.Verification.FailWith(
"Subject has " + path + subjectProperty.Name + " that the other object does not have.");
}
return compareeProperty;
}
public override string ToString()
{
return "Match property by name and type (or throw)";
}
}
public class TryMatchByNameAndTypeRule : IMatchingRule
{
public PropertyInfo Match(PropertyInfo subjectProperty, object expectation, string propertyPath)
{
PropertyInfo compareeProperty = expectation.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.SingleOrDefault(pi => pi.Name == subjectProperty.Name && pi.PropertyType == subjectProperty.PropertyType);
return compareeProperty;
}
public override string ToString()
{
return "Try to match property by name and type";
}
}
```
Comments: Fixed in commit https://fluentassertions.codeplex.com/SourceControl/changeset/3c0f594993f6c69e9e2c5c09d213edb44c771648