Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BeEquivalentTo compares explicitly implemented methods of internal interfaces #2811

Closed
chklauser opened this issue Nov 11, 2024 · 4 comments · Fixed by #2851
Closed

BeEquivalentTo compares explicitly implemented methods of internal interfaces #2811

chklauser opened this issue Nov 11, 2024 · 4 comments · Fixed by #2851
Assignees

Comments

@chklauser
Copy link

chklauser commented Nov 11, 2024

Description

I am comparing objects that inherit from a base class from a library assembly that I don't control. That base class implements properties of an internal interface explicitly. Since #2794 / 6.12.2 these explicitly implemented properties are now compared.

This is problematic because

  1. I cannot exclude these properties using .Excluding (or .For(..).Exclude(..)) because I cannot name the property. I cannot name the property because I cannot name the interface (it's internal).
  2. IncludingAllDeclaredProperties doesn't seem to have an effect. Contrary to what the doc comment on the method says, the explicitly implemented property of the internal interface seems to be treated as a public property declared on my type. Sure, interface implementations are technically public, but I would expect the visibility of the interface to "win" here.

Reproduction Steps

// Assembly A (not under my control)
internal interface IEntity {
  bool IsValid { get; }
}

public class Base(bool v) : IEntity {
  bool IEntity.IsValid { get ; } = v;
}

// Assembly B (my assembly)
// references assembly A
class MyClass(bool v) : Base(v) {
}
// Objects should be equivalent because internal interfaces are ignored.
new MyClass(true).Should().BeEquivalentTo(new MyClass(false));

Expected behavior

Internal interfaces are ignored for BeEquivalentTo.

Actual behavior

Explicit property implementations of internal interfaces are considered for BeEquivalentTo.

Regression?

This worked as expected in 6.12.1. It is broken in 6.12.2.

Known Workarounds

Use the IMemberInfo overload of .Excluding.

Configuration

.NET 8

Other information

No response

Are you willing to help with a pull-request?

No

@chklauser chklauser added the bug label Nov 11, 2024
@dennisdoomen
Copy link
Member

You're right. If the interface is internal, then you can never access that explicit interface implementation, and thus we should not treat them as public.

@dennisdoomen dennisdoomen self-assigned this Nov 11, 2024
@dennisdoomen
Copy link
Member

On second thought, we can't easily fix this. FA doesn't know whether that interface is visible for your code. It could be internal within your own project. It could be internal in a different project and you use InternalsVisibleTo. So, I think we'll add an option called ExcludingExplicitlyImplementedProperties to v7.

In the meantime, you can use the overload of Excluding that takes an Expression<Func<IMemberInfo, bool>> to exclude that property using a string like Namespace.IEntity.IsValid

@chklauser
Copy link
Author

Yes, that sounds entirely reasonable. Totally forgot about the IMemberInfo overload. I have added it to the issue as a workaround. That also means that this issue does not prevent us from upgrading to 6.12.2.

I'll close the issue then. The behavior is consistent and there is a workaround.

@chklauser chklauser closed this as not planned Won't fix, can't repro, duplicate, stale Nov 19, 2024
@dennisdoomen dennisdoomen reopened this Nov 20, 2024
@dennisdoomen
Copy link
Member

I'll keep it open to implement the ExcludingExplicitlyImplementedProperties in v7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants