Fred Tingaud 16f6c0aecf
Inline adoc when include has no additional value (#1940)
Inline adoc files when they are included exactly once.

Also fix language tags because this inlining gives us better information
on what language the code is written in.
2023-05-25 14:18:12 +02:00

130 lines
3.6 KiB
Plaintext

== Why is this an issue?
When an interface inherits from two interfaces that both define a member with the same name, trying to access that member through the derived interface will result in the compiler error ``++CS0229 Ambiguity between 'IBase1.SomeProperty' and 'IBase2.SomeProperty'++``.
So instead, every caller will be forced to cast instances of the derived interface to one or the other of its base interfaces to resolve the ambiguity and be able to access the member. Instead, it is better to resolve the ambiguity in the definition of the derived interface either by:
* renaming the member in one of the base interfaces to remove the collision
* also defining that member in the derived interface. Use this only if all copies of the member are meant to hold the same value.
=== Noncompliant code example
[source,csharp]
----
public interface IBase1
{
string SomeProperty { get; set; }
}
public interface IBase2
{
string SomeProperty { get; set; }
}
public interface IDerived : IBase1, IBase2 // Noncompliant, accessing IDerived.SomeProperty is ambiguous
{
}
public class MyClass : IDerived
{
// Implements both IBase1.SomeProperty and IBase2.SomeProperty
public string SomeProperty { get; set; } = "Hello";
public static void Main()
{
MyClass myClass = new MyClass();
Console.WriteLine(myClass.SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IBase1)myClass).SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IBase2)myClass).SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IDerived)myClass).SomeProperty); // Error CS0229 Ambiguity between 'IBase1.SomeProperty' and 'IBase2.SomeProperty'
}
}
----
=== Compliant solution
[source,csharp]
----
public interface IDerived : IBase1, IBase2
{
new string SomeProperty { get; set; }
}
public class MyClass : IDerived
{
// Implements IBase1.SomeProperty, IBase2.SomeProperty and IDerived.SomeProperty
public string SomeProperty { get; set; } = "Hello";
public static void Main()
{
MyClass myClass = new MyClass();
Console.WriteLine(myClass.SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IBase1)myClass).SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IBase2)myClass).SomeProperty); // Writes "Hello" as expected
Console.WriteLine(((IDerived)myClass).SomeProperty); // Writes "Hello" as expected
}
}
----
or
[source,csharp]
----
public interface IBase1
{
string SomePropertyOne { get; set; }
}
public interface IBase2
{
string SomePropertyTwo { get; set; }
}
public interface IDerived : IBase1, IBase2
{
}
----
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Rename or add members "{X}" and "{Y}" to this interface to resolve ambiguities.
** Note that the ellipsis at the end should only be displayed when there are more than two methods to override
=== Highlighting
* Primary: interface name
* Secondary: Implemented interfaces with colliding members
** message: Rename or add this ambiguous member.
'''
== Comments And Links
(visible only on this page)
=== on 8 Dec 2015, 09:12:07 Tamas Vajk wrote:
\[~ann.campbell.2] LGTM. (changed the message and the code samples)
=== on 8 Dec 2015, 15:12:11 Ann Campbell wrote:
\[~tamas.vajk] I've updated the SQALE remediation (constant to linear) to correspond to your message change
=== on 1 Dec 2016, 14:10:33 Tamas Vajk wrote:
\[~ann.campbell.2] I know it's not ideal, but I'm reverting this back to a constant effort rule. We're migrating to Rule-API based descriptions, and in .NET we don't have linear regression function support.
endif::env-github,rspecator-view[]