#726 – Listing all Types within a Namespace

You can’t directly list out all types within a namespace.  But you can get all types within a particular assembly and then filter out only the types that match a particular namespace.

        static void Main()
        {
            // Dump all types from in a specified namespace
            DumpTypesForNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication1");
            DumpTypesForNamespace(Assembly.GetExecutingAssembly(), "ConsoleApplication1.Dog");

            int i = 1;
        }

        private static void DumpTypesForNamespace (Assembly assem, string theNamespace)
        {
            Console.WriteLine(string.Format("[{0}]", theNamespace));

            foreach (Type t in assem.GetTypes())
            {
                if (t.Namespace == theNamespace)
                {
                    string dump =
                        string.Format("{0}\n  ({1} in {2})\n", t.FullName, TypeIndicator(t), t.Namespace);

                    Console.WriteLine(dump);
                }
            }
            Console.WriteLine("\n");
        }

        private static string TypeIndicator(Type t)
        {
            string typeIndicator = "?";

            if ((t.BaseType != null) &&
                (t.BaseType.FullName == "System.MulticastDelegate"))
                typeIndicator = "delegate";

            else if (t.IsClass)
            {
                if (t.IsNested)
                    typeIndicator = "Nested class";
                else
                    typeIndicator = "class";
            }
            else if (t.IsInterface)
                typeIndicator = "interface";

            else if (t.IsValueType)
                typeIndicator = "struct";

            else if (t.IsEnum)
                typeIndicator = "enum";

            return typeIndicator;
        }

726-002

#725 – Dumping Out a List of Types in an Assembly

You can use reflection to get a list of all types in an assembly.  Each type is represented by an instance of the Type class, which you can then query to get information about the type.

Below is a code sample that dumps out all types defined in the running assembly.  Notice that we identify each type as one of the five custom types that you can define.

        static void Main()
        {
            foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
            {
                string dump =
                    string.Format("{0}\n  ({1} in {2})\n", t.FullName, TypeIndicator(t), t.Namespace);

                Console.WriteLine(dump);
            }
        }

        private static string TypeIndicator(Type t)
        {
            string typeIndicator = "?";

            if ((t.BaseType != null) &&
                (t.BaseType.FullName == "System.MulticastDelegate"))
                typeIndicator = "delegate";

            else if (t.IsClass)
            {
                if (t.IsNested)
                    typeIndicator = "Nested class";
                else
                    typeIndicator = "class";
            }
            else if (t.IsInterface)
                typeIndicator = "interface";

            else if (t.IsValueType)
                typeIndicator = "struct";

            else if (t.IsEnum)
                typeIndicator = "enum";

            return typeIndicator;
        }

#724 – Fully Qualified Names for Types

Every type in C# has a fully qualified name that consists of:

  • Dotted notation indicating the namespace hierarchy in which the type appears
  • Dotted notation indicating the type hierarchy, if the the type is nested

In the example below, the fully qualified name for the DogCollar type would be DogLibrary.MainTypes.Dog.DogCollar.

namespace DogLibrary
{
    namespace MainTypes
    {
        public class Dog
        {
            public class DogCollar
            {
            }
        }
    }
}

You can always refer to a type using its fully qualified name. For example:

            DogLibrary.MainTypes.Dog.DogCollar dc = new DogLibrary.MainTypes.Dog.DogCollar();

#723 – New Methods in Subclass May Not Be Visible in Derived Classes

You can use the new keyword in a subclass to hide a method in the parent class.  The new implementation of the method will now be used in the context of the subclass.

If you call this method in a subclass of the subclass, however, the method called depends on the accessibility of the new method.  If the new method is private, it is not visible in the lowest level class and so the original member in the base class is called.

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public void DoBark()
        {
            Bark();
        }

        private new void Bark()
        {
            Console.WriteLine("Terrier: Woof");
        }
    }

    public class Yorkshire : Terrier
    {
        public void DoBark()
        {
            // Dog.Bark is called
            Bark();
        }
    }

 

            Dog d = new Dog();
            d.Bark();

            Terrier t = new Terrier();
            t.DoBark();

            Yorkshire y = new Yorkshire();
            y.DoBark();

#722 – Local Variable Declarations May Not Always Hide Class Members

A local variable declaration in a method may hide a class member in the containing class, if the two names are the same.  In general, a declaration within an inner scope may hide a member within the outer (containing) scope.

A inner declaration might not hide an outer member, however, if one of the names can be invoked (e.g. a method) and one cannot be invoked (e.g. a variable declaration).

In the example below, the local variable Name in the inner scope does not hide the method Name in the outer scope.

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

        public void Name(string name)
        {
            MyName = name;

            Console.WriteLine(string.Format("New name is {0}", MyName));
        }

        public void Bark()
        {
            // Local variable does not hide Dog.Name method
            string Name = "Franklin Roosevelt";

            Console.WriteLine(Name);

            this.Name("Bob");
        }
    }

#721 – Local Variable Declarations Can Hide Class Members

It’s possible to declare a variable in a method that has the same name as one of the class members in the class where the method is defined.  The local variable is said to hide the class member.

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

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

        public void Bark()
        {
            // Local variable Hides Dog's Name property
            string Name = "Franklin Roosevelt";

            Console.WriteLine(string.Format("{0} says WOOF", Name));

            // Can still access Dog.Name via this pointer
            Console.WriteLine(string.Format("I'm {0}", this.Name));
        }
    }


Notice that you can still access the class-level Name property by using the this keyword.

While it’s possible to hide a class member in this way, it’s generally considered to be bad practice.  When you make Name mean different things, depending on what part of the code you’re in, this can lead to confusion.

#720 – Location of Declarations within A Method Does Matter

When declaring members in a class, you can declare the members anywhere in the class, even placing a declaration after some code that references the declared member.

When you declare variables within a method, however, a variable must be declared before it is used.  Compiling the code below will result in a compile-time error, since the leadin variable in the method RevealNames 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(leadin);
            Console.WriteLine(string.Format("{0} is really {1}", Name, secretName));
            string leadin = "Did you know?";
        }

        private string secretName;
    }

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

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