#719 – Location of Declarations within A Class Doesn’t Matter

Within the code for a class, you can declare members either before or after they are used.

In the example below, the Name property is declared earlier in the class than it is used.  But the secretName field is declared after it is used.

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

        public Dog(string name)
        {
            Name = name;
            secretName = "His Great Terribleness Mr. Bites-a-Lot";
        }

        public void RevealNames()
        {
            Console.WriteLine(string.Format("{0} is really {1}", Name, secretName));
        }

        private string secretName;
    }
Advertisements

#718 – Scope

In C#, every name has a scope.  The scope of a name is the region of code in which you can refer to that name using just the unqualified name.

Here are some examples:

  • The scope of a type defined within a namespace is all code also defined in that namespace
  • The scope of a member declared in a class is the body of that class
  • The scope of a parameter declared in a method is the body of that method
  • The scope of a local variable is the method in which it is defined
  • The scope of a local variable defined within a block is the body of that block

#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;
        }
    }

#716 – How Derived Classes Can Access Protected Members

Marking a class member as protected indicates that the member can be used from code within that class or from code in a derived class.

The derived class, however, can only access a protected member through an instance of the derived class or one of its own subclasses.

In the example below, SecretName is defined in Dog as protected.  It can be accessed in the Terrier subclass only through a Terrier instance, not a Dog instance.

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

        public Dog(string name, string secretName)
        {
            Name = name;
            SecretName = secretName;
        }
    }

    public class Terrier : Dog
    {
        public Terrier(string name, string secretName) : base(name, secretName)
        {
        }

        public void GatherIntel(Dog d, Terrier t)
        {
            // Ok
            Console.WriteLine(string.Format("Dog:{0}, Terrier:{1}", d.Name, t.Name));

            // Ok
            Console.WriteLine(string.Format("Me:{0}, Him:{1}", this.SecretName, t.SecretName));

            // Compiler error
            Console.WriteLine(string.Format("Dog is {0}", d.SecretName));
        }
    }

#715 – Private Members Are Not Visible in a Derived Class

Class members declared with an accessibility level of private are accessible only within the code for the class in which they are declared.  They are not accessible from a derived class.

In the example below, dogData is a private member of the Dog class, so it is not visible within the Terrier class (which inherits from Dog).

    public class Dog
    {
        // Stuff that's clearly public
        public string Name { get; set; }
        public int Age { get; set; }

        private int dogData;

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
            dogData = 12;
        }
    }
    public class Terrier : Dog
    {
        public Terrier(string name, int age) : base(name, age)
        {
        }

        public void Snarl()
        {
            // Compiler error: dogData is inaccessible due to its protection level
            Console.WriteLine(dogData);
        }
    }

#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));
        }
    }

#713 – Declare Accessibility Explicitly

It’s always good practice to explicitly declare the accessibility of an item, for class members, struct members, and classes.  Declaring the accessibility makes it clear what the accessibility is for the item and avoids someone having to recall what the default accessibility is.

    public class Dog
    {
        // Stuff that's clearly public
        public string Name { get; set; }
        public int Age { get; set; }

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Stuff that's clearly private
        private int numBarks;

        // Not obvious--private or public?
        //   (private, because class members are private by default)
        void DoBark()
        {
            Console.WriteLine("WOOF");
        }
    }