#799 – Interface Members Are Implicitly Public

When you declare an interface, you cannot use access modifiers on interface’s member.  An interface makes a collection of members available to code that accesses a class implementing that interface.  So it makes sense that the interface members are public.

    public interface IBark
    {
        int BarkCount { get; set; }
        void Bark(string woofSound, int count);
    }

When you implement an interface, you must mark the interface members as public.

    public class Dog : IBark
    {
        public int BarkCount { get; set; }

        public void Bark(string woofSound, int count)
        {
            for (int i = 1; i <= count; i++)
                Console.WriteLine(woofSound);
        }
    }

If you implement the interface explicitly, the members are implicitly public and you cannot mark them with access modifiers.

        int IBark.BarkCount { get; set; }

        void IBark.Bark(string woofSound, int count)
        {
            for (int i = 1; i <= count; i++)
                Console.WriteLine(woofSound);
        }

#797 – Setting Accessibility for Property Accessors

By default, the accessibility of a property accessor matches the accessibility of the property itself.  You can also explicitly set the accessibility of an accessor, within certain limitations.

When setting the accessibility of a property accessor:

  • You can’t make an accessor more accessible than the property itself
  • You can’t specify the exact same accessibility on the accessor as the property
  • The property must have both get and set accessors defined
  • You can only set accessibility on one of the accessors, not both
  • You can’t set the accessibility of an accessor on a property in an interface
  • When overriding a virtual property in a parent class, you must replicate the accessibility of the accessors in the parent’s class exactly

The bottom line–you can make one of the accessors a bit more restrictive than the other.

        public string Name { get; protected set; }

#796 – Default Accessibility for Property Accessors

When you implement a property in a class, you define the property’s accessibility, e.g. public, private, protected, internal or protected internal.

Client code uses a property like a field, reading and writing the property’s value.  The property is actually implemented as a two accessor methods.  The get accessor is called when some code reads the property’s value and the set accessor is called when some code write’s the property’s value.

By default, the accessibility of the two property accessors matches the accessibility of the property itself.

        // Property is public, so both get and set accessors are public
        public string Name { get; set; }

        // Property is private, so both get and set accesors are private
        private string SecreteName { get; set; }

#790 – Property get and set Accessors Can Have Different Access Modifiers

When you implement a property in a class, you can specify different access modifiers for the get vs. set accessors.  This is true whether you are implementing the property yourself, or using an automatic property.

Different combinations of access modifiers include:

  • get/set both public – client can read/write property value
  • get/set both private – client has no access to the property
  • get public, set private – property is read-only
  • get private, set public – property is write-only
        // get/set both public
        public string Name { get; set; }

        // get/set both private
        private string SecretName { get; set; }

        // public get => read-only
        public string CalcName { get; private set; }

        // public set => write-only
        public string WriteOnlyName { private get; set; }

#787 – Avoid Public Fields in a Class

When you declare a field in a class, you can set its accessibility to: public, private, protected, internal, or protected internal.

In general, you should declare fields as private or protected, instead of making them public.  For purposes of encapsulation, you typically expose public data members as properties, rather than fields.  This hides the implementation details of the data item from users of the class and makes it easier to change those details without changing or affecting code that uses the class.

Instead of this:

public class Dog
{
    // A field
    public string Name;
}

You should do this:

    public class Dog
    {
        // A property
        public string Name { get; set; }
    }

Or this:

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                // do other stuff
                name = value;
            }
        }

#717 – Class Members Can’t Be More Accessible Than Their Type

When specifying the accessibility for a class member, the member’s type must be at least as accessible as the member itself.  For methods, the return type and types of all parameters must be as accessible as the method.

This makes sense–client code can’t access a class member if it can’t access that member’s type.  Client code also can’t invoke a method if it can’t access the type of all the method’s parameters and return type.

In the example below, because the DogCollar type is internal, the Collar property must be internal or private.

    internal class DogCollar
    {
        public string Material { get; set; }
        public double Size { get; set; }
    }

    public class Dog
    {
        public string Name { get; set; }

        // Error: DogCollar less accessible (internal) than Collar (public)
        public DogCollar Collar { get; set; }

        public Dog(string name)
        {
            Name = name;
        }
    }

#714 – Accessibility of a Public Method in an Internal Type

When you declare a class with an accessibility of internal, the class is usable only from code within the same assembly.  If this class then contains a member whose accessibility is public, that member is still limited to an accessibility level of internal.  A member of a class cannot be more accessible than the class itself.

This makes sense.  If we have code that doesn’t know about about a DogCollar class, it certainly can’t invoke the ReportSize method of the DogCollar class.

    // Can only use DogCollar within this assembly
    internal class DogCollar
    {
        // Marked as public, but effectively internal
        public double Size { get; set; }

        public DogCollar(double size)
        {
            Size = size;
        }

        // Also effectively internal
        public void ReportSize()
        {
            Console.WriteLine(string.Format("Collar is {0} in long", Size));
        }
    }