Is it a breaking change that modifying the access modifier of a public property?

前端 未结 5 826
太阳男子
太阳男子 2021-02-01 05:22

If I change the access modifier of the setter of a public property from private to public, is that causes any breaking change in the other assemblies that refer it?

相关标签:
5条回答
  • 2021-02-01 05:58

    It is a breaking change, in that it may cause existing code to no longer compile.

    Some languages do not allow you to override a property without overriding all visible accessors. VB is such a language.

    Say you have the following C# class:

    namespace TestLibrary
        public class A {
            public virtual int X { 
                get { return 0; } 
                private set { Console.WriteLine("A.set_X called."); } 
            }
        }
    }
    

    In a VB project that references your library, you have a class definition:

    Class B : Inherits TestLibrary.A
        Public Overrides ReadOnly Property X As Integer
            Get
                Return MyBase.X
            End Get
        End Property
    End Class
    

    Notice the ReadOnly modifier on the property. This is required in VB, because you are only defining the getter. If you leave it out, you get a compile-time error:

    Property without a 'ReadOnly' or 'WriteOnly' specifier must provide both a 'Get' and a 'Set'.

    Now, remove the private modifier from the setter in your C# class:

    namespace TestLibrary
        public class A {
            public virtual int X { 
                get { return 0; } 
                set { Console.WriteLine("A.set_X called."); } 
            }
        }
    }
    

    You will now get a compile-time error in your VB code:

    'Public Overrides ReadOnly Property X As Integer' cannot override 'Public Overridable Property X As Integer' because they differ by 'ReadOnly' or 'WriteOnly'.

    The same code that references your library does not compile after you make the change, so it is a breaking change.

    0 讨论(0)
  • 2021-02-01 06:07

    This depends on how strict you want to be about "breaking change".

    One definition is: does it break the build or execution of the referring code.

    Another is, can the other code determine that you made the change.

    By the first definition, this is not a breaking change. By the second definition, it is a breaking change.

    0 讨论(0)
  • 2021-02-01 06:11

    It might be, if those other assemblies use reflection to test for the presence of the setter.

    But early-bound code will not break.

    Another thing to consider is whether this is a change in semantics. If the property was formerly set only during construction, and now can be modified at any time, that definitely could break consumers who cached the value, used it as a Dictionary key, etc.

    0 讨论(0)
  • 2021-02-01 06:12

    Since the visibility of the property is increased now there should not be any problems with statically linked assemblies and static references -- those assemblies just treated your property as read-only until now and they continue doing so.

    The only problem that might potentially arise here is if some assemblies use reflection to get information about your properties and perform some actions.

    For example, if this is a property of a business object and you use data binding to show your data in some control, like GridView or ListView (independent from the actual framework), it might be that this property will be recognized as "updateable" now and the user might change some values you (and some other assemblies) considered immutable so far.

    0 讨论(0)
  • 2021-02-01 06:24

    UPDATE: This question was the topic of my blog in January 2012. Thanks for the great question!


    I assume that by "breaking change" you mean "when I recompile code that depended on this assembly, does code that used to compile still compile?"

    By that definition, strictly speaking, yes, making a property setter public that used to be private is a breaking change. Suppose you have this code:

    // Assembly Alpha
    public class Charlie
    {
        public int P { get; private set; }
    }
    public class Delta
    {
        public int P { get; set; }
    }
    

    And then in another assembly that references Alpha:

    // Assembly Echo
    class Foxtrot
    {
        static void M(Action<Charlie> f) {}
        static void M(Action<Delta> f) {}
        static void Golf()
        {
            M(y=>{y.P = 123;});
        }
    }
    

    You compile assembly Echo. Class Foxtrot has a method Golf which does overload resolution on M. M has two overloads; one that takes a action on Charlie and one that takes an action on Delta. If lambda parameter y is of type Charlie then the lambda body produces an accessibility error, and therefore that overload of M is not an applicable candidate. Overload resolution chooses the second overload and compilation succeeds.

    Now you change assembly Alpha so that Charlie.P's setter is public. You recompile Echo. Now you get an overload resolution error because both overloads of M are equally valid and neither is better than the other. Compilation of Echo fails due to the change in Alpha. Your change to Alpha was a breaking change.

    The question is not "is this a breaking change?" It clearly is; almost every change is some kind of breaking change. The question should be whether the breaking change will actually in practice break anyone, and if so, what is the cost of fixing the break compared to the benefit of the new feature?

    0 讨论(0)
提交回复
热议问题