I am reading Beginning Visual C# 2012.
Consider:
using System;
using System.Collections.Generic;
using System.Text;
namespace Ch10Ex01
{
class MyClass
{
public readonly string Name;
private int intVal;
public int Val
{
get { return intVal; }
set
{
if (0 <= value && value <= 10)
intVal = value;
else
throw (new ArgumentOutOfRangeException("Val", value,
"Val must be assigned a value between 0 and 10."));
}
}
public override string ToString()
{
return "Name: " + Name + "\nVal: " + Val;
}
private MyClass() : this("Default Name")
{
}
public MyClass(string newName)
{
Name = newName;
intVal = 0;
}
}
}
Explanation in the book: Note that I've used this ("Default Name") to ensure that Name gets a value if this constructor ever gets called, which is possible if this class is used to derive a new class. This is necessary as not assigning a value to the Name field could be a source of errors later.
What's puzzling me: How can it be used in a derived class as it's "private"? What does this ("Default Name") mean? How does the object get the "Default Name" as its name?
What's puzzling me: How can it be used in a derived class as it's "private"? What does this("Default Name") mean? **How does the object get the "Default Name" as its name?
You are right to be puzzled!
That code sample does not call the default constructor at all - and because it is private, nothing else can call it without using reflection (not even a derived class; it would have to be at least protected for a derived class to call it - or the derived class would have to be nested within the base class).
In the sample code, the object does not get "Default Name" as its value.
So it's a typo or an error in the book.
The correct solution to what the book is describing is to:
Name at field scope. This ensures that it is impossible to fail to initialise it, no matter what other constructors are written in this or any derived class.Like so:
class MyClass
{
public readonly string Name = "Default Name";
private int intVal;
public int Val
{
get
{
return intVal;
}
set
{
if (0 <= value && value <= 10)
intVal = value;
else
throw (new ArgumentOutOfRangeException("Val", value,
"Val must be assigned a value between 0 and 10."));
}
}
public override string ToString()
{
return "Name: " + Name + "\nVal: " + Val;
}
public MyClass(string newName)
{
Name = newName;
intVal = 0;
}
}
Note that it can often be useful to declare a private default constructor which is called by other constructors - but the declaring class has to actually use it.
Also note that if you declare a non-default constructor in a base class and do not declare a default constructor at all, any derived class must call one of the existing base class constructors.
For example given the class definition above, then both the following class declarations will cause a compile error MyClass' does not contain a constructor that takes 0 arguments:
class MyDerivedClass1: MyClass
{
public MyDerivedClass1() // Compile error
{
}
}
class MyDerivedClass2: MyClass
{
// No constructor declared at all. Also a compile error.
}
To fix the error, MyDerivedClass has to call an existing constructor:
class MyDerivedClass: MyClass
{
public MyDerivedClass(): base("My new name")
{
}
}
So what use is a private constructor
A fairly typical use is to put common initialisation code into a default constructor. Sometimes, however, you don't want the caller to be able to default-construct the type - in which case you can make the default constructor private.
That way, you can still use the default constructor for common initialisation but you prevent code outside the class from doing it, for example:
class Test
{
public readonly int IntValue;
public readonly string StringValue;
private Test()
{
// Do common initialisation.
}
public Test(int intValue): this()
{
IntValue = intValue;
}
public Test(string stringValue): this()
{
StringValue = stringValue;
}
}
Often you could just use a private init() method to do the common initialisation, but if you are initialising a readonly field you must use a constructor to do so. In that case, a private constructor must be used instead of an init() method.
Another use of a private default constructor is to prevent any instantiation of the type at all (you just declare a private default constructor and no other constructors at all).
In .Net 1.x that was the only way to do so - but subsequent versions of .Net introduced static classes which for most cases removed the need to use a private constructor for that type.
You might also declare a private constructor to force the use of a static factory method to instantiate the type.
Just for completeness, here's a contrived example that demonstrates how a private constructor can be called from a nested derived class:
class OuterClass
{
public readonly string Value;
private OuterClass(): this("Default Value")
{
}
public OuterClass(string value)
{
Value = value;
}
public OuterClass GetInnerClass()
{
return new InnerClass();
}
private class InnerClass: OuterClass
{
}
}
With that class definition, the following code will print "Default Value":
OuterClass test = new OuterClass("Test");
Console.WriteLine(test.GetInnerClass().Value);
Personally I've never had to write a nested class that derives from its containing class, but it's possible if you need to do it for some reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With