Uploaded image for project: 'Rules Repository'
  1. Rules Repository
  2. RSPEC-3444

Interfaces should not simply inherit from base interfaces with colliding members

    XMLWordPrintable

    Details

    • Type: Code Smell Detection
    • Status: Active
    • Resolution: Unresolved
    • Labels:
    • Message:
      Hide
      Rename or add ambiguous members defined in interfaces "{X}" and "{Y}" ( "MyMethod(string), "OtherMethod(string, Foo)", …)

      -- Note that the ellipsis at the end should only be displayed when there are more than two methods to override
      Show
      Rename or add ambiguous members defined in interfaces "{X}" and "{Y}" ( "MyMethod(string), "OtherMethod(string, Foo)", …) -- 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.
    • Default Severity:
      Minor
    • Impact:
      Low
    • Likelihood:
      Low
    • Default Quality Profiles:
      Sonar way
    • Covered Languages:
      C#
    • Remediation Function:
      Constant/Issue
    • Constant Cost:
      5min
    • Analysis Scope:
      Main Sources
    • ReSharper:
      PossibleInterfaceMemberAmbiguity

      Description

      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

      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

      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

      public interface IBase1
      {
        string SomePropertyOne { get; set; }
      }
      
      public interface IBase2
      {
        string SomePropertyTwo { get; set; }
      }
      
      public interface IDerived : IBase1, IBase2
      {
      }
      

        Attachments

          Activity

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            ann.campbell.2 Ann Campbell
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated: