Fog Creek Software
Discussion Board




Some thoughts, some .NET questions


Some questions, some thoughts thought aloud.

(1) Begining with a trivial one, what is the default access specifier/class modifier in C#. I ask because I have  seen some sample code on the Net with methods that are a part of the public interface of the class/object. I  was confused because C++ had the public modifier as the default for structs and private for classes.

Ok, I checked this and noted a difference. While the default scope of members in a VB.NET class is public, in  C# every member _has_ to explicitly given the public access specifier in order for it to be included in the  public interface of the object. I noted this with an example in both the languages:

[VB.NET]
Imports System

Class  Person

        Dim FullName as String
    
        Sub New(ByVal FullName As String)
                MyClass.FullName= FullName
        End Sub
    
    Sub PrintName()
                Console.WriteLine()
                Console.WriteLine()
                Console.WriteLine("Full Name: {0}", FullName)
                Console.WriteLine()
                Console.WriteLine()
    End Sub
    
End Class

Module Main
    Sub Main()
                Dim Sathyaish As Person = New Person("Sathyaish Chakravarthy")
                Sathyaish.PrintName
    End Sub
End Module
[/VB.NET]

[C#]
using System;

namespace Practice
{

        class Person
        {

                private string FullName;

                public Person(string FullName)
                {
                    this.FullName=FullName;
                }

                public void PrintName()
                {
                        Console.WriteLine("\n\nFull Name: {0}", FullName);
                }
        } //End of Class Person

        class App
        {
                public static void Main(string[] args)
                {
                        Person Sathyaish = new Person("Sathyaish Chakravarthy");
                        Sathyaish.PrintName();
                }
        } //End of Class App
} //End of namespace Practice
[/C#]

Sorry for the bad indentation. I wrote them using the MS DOS editor.

Removing the public access specifier from the functions, even from the constructor gave me a message like:

[/COMPILE ERROR]'Practice.Person.Person(string)' is inaccessible due to its protection level[/COMPILE  ERROR]

The question that springs up from this observation is: Are constructors also required to have access  specifiers? If yes, can there also be privately declared constructors? I ask because my memory has the relics  of a C++ course I attended where there was some talk about having private constructors triggered. I guess it  was in the context of virtual base classes.

(2)  Reading an article on the Net, I was intrigued by Array Covariance. The example demonstrated how an  array of elements of a base class type could be polymorphic to caste themselves to a derived type; basically  the concept of polymorphism. However, the line that transfered array contents intrigued me and I thought I  could use that to copy two dymanic/open-ended arrays as well.

I haven't quite mastered the syntax, so this code I reproduce will be syntactically incorrect, but what I saw  was along the lines of:

[PSUEDO CODE]
using System;

namespace Practice
{

class Person
{
    public string FullName;
    public int Age;
    public string State;
    public string City;

        public Overridable Print()
    {
        Console.Write("\n\n**********Basic Information:***********\n\n");
        Console.WriteLine("Name: {0}", FullName);
        Console.WriteLine("Age: {0}", Age);
        Console.WriteLine("State: {0}", State);
        Console.WriteLine("City: {0}", City);
    }

} //End of class Person

class Customer
    Inherits Person
{
    public int CustomerID;

    public void Overrides Print()
    {
        MyBase.Print();
        Console.WriteLine("Customer ID: {0}", CustomerID);
    }
} //End of class Customer

class App
{
    public static void main()
    {
        Customer Customers[10];
        Person Persons[10];
        
        for(int i=0; i<=9; i++)
            Customers[i] = new Customer();

        //-----------------WAS INTRIGUED BY THIS---------------------------------
        People = Customers;
        //-----------------WAS INTRIGUED BY THIS---------------------------------

        for(int i=0; i<=9; i++)
            People(i).FullName = "Customer " + Integer.toString(i);

} //End of class App

} //End of namespace Practice
[/PSUEDO CODE]

And I wanted to see if I could copy two arrays, so I tried this and it worked. First shot!

[C# CODE]
using System;

namespace Practice
{

class App
{

    public static void Main(string[] args)
    {
        int[] Arr1 = {1,2,3,4,5};
        int[] Arr2;

        Arr2 = Arr1;
        
        for(int i=0; i<=Arr2.Length-1; i++)
            Console.WriteLine("Arr2[{0}] = {1}", i, Arr2[i]);

    } //End of main
} //End of Class App

} //End of namespace Practice
[/C# CODE]

(3) In the code snippet below:

[VB.NET CODE]
Imports System

Class Person
    Dim FullName as String
End Class

Class Employee
    Inherits Person

End Class


Module Test

    Sub FillArray(ByVal People() as Person)
        For Index as Integer = 0 To People.Length -1
            People(Index) = New Person
        Next Index
    End Sub

    Sub Main()
        Dim Employees(9) as Employee
        FillArray(Employees)
    End Sub
End Module
[/VB.NET CODE]

I get a runtime exception error in this because of this statement:

            People(Index) = New Person

and not because of passing an Employee type array to a Person type, which is strictly a legal polymorphic  behaviour. Am I right in thinking so?

(4) Why would you want to box and unbox a fundamental value type? Can someone gimme a real life  instance, please.

(5) Is there a VB.NET equivalant of the C# unchecked construct? For instance, I tested this code which gave a  runtime overflow exception, as expected:

Imports System

Module Test
    Sub Main()
        Dim i as Integer, lng as Long
        i =0
        
        lng = 1000
        i = ctype(lng, Integer)
        Console.WriteLine("The value of i is (within Integer range): {0}", i)
        
    'Unchecked
        lng = (2^31)+1
        i = ctype(lng, Integer)
        Console.WriteLine("The value of i is (outside of Integer range): {0}", i)
    'End Unchecked
        
        
    End Sub
End Module

(6) Is it possible to box a derived UDT to it's base type? Is the reverse possible?

(7) With regard to this (http://blogs.msdn.com/ericlippert/articles/136883.aspx) article of Eric Lippert's, I  wanna know whether it is necessary to set the object Person to Nothing in which of the two cases below:

CASE 1: I don't think it is necessary here.

[VB6 CODE]
Sub Main()
    Dim Post as Post
    Set Post = New Post
    Call MakeAPostOnJoS(Post)
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'I don't think this is required
    Set Post = Nothing
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End Sub


Public Sub MakeAPostOnJoS(PostObj as Post) 'Member of Class Poster, Instancing GlobalMultiUse
    With PostObj
        .Subject = Subject
        .Message = Message
        .PostersName = MyName
        .PostersEmailAddress = Email
        Call .Submit
    End With
End Sub
[VB CODE]



CASE 2: I think it IS necessary here.

[VB6 CODE]
Sub Main()
    Dim Post as Post

    ''''''''''''''''Set Post = New Post

    Call MakeAPostOnJoS(Post)
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'I think this IS required. Or is it?
    Set Post = Nothing
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End Sub


Public Sub MakeAPostOnJoS(PostObj as Post) 'Member of Class Poster, Instancing GlobalMultiUse
Set PostObj = New Post
    With PostObj
        .Subject = " "
        .Message = " "
        .PostersName = " "
        .PostersEmailAddress = " "
        Call .Submit
    End With
End Sub
[VB CODE]

(8) Am I right in thinking thus: C#/VB.NET can afford the MyBase pointer because they don't allow multiple  inheritence and the ambiguities that come with virtual base classes. For instance,

int main()
{
    Derived Dvar;
    Dvar.base1::DoSomething();
    Dvar.base2::DoSomething();
    
    Dvar.base1::CommonGrandParent.Foo = "Bar";
    Dvar.base2::CommonGrandParent.Foo = "Bar";
}

(9) When public members of a base class are also inherited by a derived class, doesn't this render the  protected access specifier redundant? Why would you want to use protected? Because you wanted the  protected member not to be accessible by people outside your lineage? Does a protected member become a  part of the public interface of an object? If the answer is yes, then there's no use of the protected access  specifier. It makes sense only if the protected member doesn't become a part of the public interface exposed  by an object.

(10) Can an overridable method also be overloaded in the derived class?

(11) A statement I read says, "When you are overriding a method, the access of the overriding method must  be the same as the method being overridden."

Is this because if you changed the access of the overriding method to, say, Private while the overridable  method was a private one, the original interface of the base class inherited in the derived class is broken?

Estudiantin
Wednesday, June 02, 2004

"Are constructors also required to have access  specifiers? If yes, can there also be privately declared constructors?"

Yes, and yes. You could, for example, have private constructors if you wanted to have your class always be created by a static factory method, or perhaps the class is a singleton. For example:

public class SingletonClass
{
    private SingletonClass(...some params...)
    {
    }

    public static SingletonClass Instance
    {
        get
        {
            if (instance == null)
                instance = new SingletonClass(...);
            return instance;
        }
    }
    private static SingletonClass instance = null;
}

Brad Wilson (dotnetguy.techieswithcats.com)
Wednesday, June 02, 2004

(1) Take a look at this URL:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vclrfdeclaredaccessibilitypg.asp

or even better (use the tree at the left to find more):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vclrfTypesAccessModifiers.asp

When your constructor has a non-public access, you can restrict how an instance of the class may be constructed. If you've ever heard of Singleton classes, they are possible through non-public constructors. If you've ever browsed through the FCL's reference, you must have come across some methods returning instances of classes that may not be instantiated by you - probably because of "protected internal" access. The "protected internal" access makes sure that no one outside the assembly containing that type can access it.

(2) There's no need to be intrigued. You can either store a value within a variable or reference to the value within a memory location. Using this syntax, a shallow copy operation is performed. It only copies the values from the expression at the right to the L-value. It's only copying the references. Both arrays will point to the same instances.

(3) VB.NET - Sorry can't understand it.

(4) For example you can have this, i.e. you can store reference and value types in a single array of "object"s.

object[] arrayOfObjects= new object[3];
int integerValue = 10;

arrayOfObjects[0] = (object) integerValue;
arrayOfObjects[1] = new Person();
arrayOfObjects[2] = new Employee();

foreach(object anObject in arrayOfObjects)
{
    Console.WriteLine(object);
}

(5) checked and unchecked keywords.

(6) Depending on the object you can go up or go down. As long as the underlying object fulfills that interface (within the hierarchy ofcourse).

(7) I didn't open that link. When you set something to Nothing or "null" (in C#), you are marking that variable being unused from that point onwards. It probably should make the code more readable and hint the GC that the variable's value is gone.

(8) Depends. You're the programmer. If you can handle anything appropriately, even global variables and goto cannot be bad. But on the whole, it's ALWAYS possible to avoid such things (if you think they are bad).

(9) When you inherit from a class. It's private members stay private, even your derived class cannot access them. It's protected members stay protected. You can access them from within your derived class but no one from outside that class can access them. The same is true for the "protected internal".

(10) Your compiler should help you with that. Try writing it and see if it works.

(11) Yes.

Green Pajamas
Wednesday, June 02, 2004

"I get a runtime exception error in this because of this statement: People(Index) = New Person"

Because a person isn't necessarily an employee, and People() is ACTUALLY an array of employees, not persons. The covariance only works for reading; when you try to write you fail, because you don't meet the container's requirements.

Brad Wilson (dotnetguy.techieswithcats.com)
Wednesday, June 02, 2004

"(7) I didn't open that link. When you set something to Nothing or "null" (in C#), you are marking that variable being unused from that point onwards. It probably should make the code more readable and hint the GC that the variable's value is gone."

And it's actually completely unnecessary, because the compiler already does this for you. It's a local reference, so the compiler knows the instant you're done with it, because it can see the entire scope of your method and see that you never use it again.

The only time you need to set things explicitly to null is to break a cycle between an object that needs to die and an object that is still alive (if both objects should die, then the cycle is irrelevant and they will be collected when nothing external references them). This is for explicitly held long-lived references. Keep in mind that registering a delegate is a form of explicitly held reference.

Brad Wilson (dotnetguy.techieswithcats.com)
Wednesday, June 02, 2004

Just two small aditional comments

(1) The default C# access modifier is "private". When you removed the "public" from the constructor, it became "private", and thus no longer accessible to App

(2) Be carefull with this. The C# compiler will early bind the call to the methods, unless you specifically declare virtual/override for them. You could end up calling Person.foo() on a Customer object even though Customer has its own foo() method, unless the foo() in Person is declared "virtual" and the foo() in Customer is declared "override".

Just me (Sir to you)
Thursday, June 03, 2004

*  Recent Topics

*  Fog Creek Home