让我感到困惑的是:它是“私有的”,如何在派生类中使用?这(“默认名称”)是什么意思?**对象如何获得“默认名称”作为其名称?
你的困惑是对的!
该代码示例根本不调用默认构造函数 - 因为它是私有的,所以没有使用反射(甚至不是派生类;它必须至少protected
是派生类调用它 - 或者派生类必须嵌套在基类中)。
在示例代码中,对象没有将“默认名称”作为其值。
所以这是书中的错字或错误。
本书所描述的正确解决方案是:
- 完全省略默认构造函数。
Name
在字段范围内初始化。这确保了初始化它是不可能失败的,无论在这个或任何派生类中编写了哪些其他构造函数。
像这样:
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;
}
}
请注意,声明一个由其他构造函数调用的私有默认构造函数通常很有用——但声明类必须实际使用它。
另请注意,如果您在基类中声明非默认构造函数并且根本不声明默认构造函数,则任何派生类都必须调用现有基类构造函数之一。
例如给定上面的类定义,那么以下两个类声明都会导致编译错误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.
}
要修复错误,MyDerivedClass
必须调用现有的构造函数:
class MyDerivedClass: MyClass
{
public MyDerivedClass(): base("My new name")
{
}
}
那么私有构造函数有什么用
一个相当典型的用途是将通用初始化代码放入默认构造函数中。但是,有时您不希望调用者能够默认构造类型 - 在这种情况下,您可以将默认构造函数设为私有。
这样,您仍然可以使用默认构造函数进行常见初始化,但您会阻止类外部的代码执行此操作,例如:
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;
}
}
通常您可以只使用私有init()
方法来进行通用初始化,但如果您正在初始化一个readonly
字段,则必须使用构造函数来执行此操作。在这种情况下,必须使用私有构造函数而不是init()
方法。
私有默认构造函数的另一个用途是完全阻止类型的任何实例化(您只需声明一个私有默认构造函数,根本没有其他构造函数)。
在 .Net 1.x 中,这是这样做的唯一方法 - 但 .Net 的后续版本引入了静态类,在大多数情况下,无需为该类型使用私有构造函数。
您还可以声明一个私有构造函数来强制使用静态工厂方法来实例化该类型。
为了完整起见,这里有一个人为的示例,演示了如何从嵌套派生类调用私有构造函数:
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
{
}
}
使用该类定义,以下代码将打印“默认值”:
OuterClass test = new OuterClass("Test");
Console.WriteLine(test.GetInnerClass().Value);
就我个人而言,我从来不需要编写从其包含类派生的嵌套类,但如果您出于某种原因需要这样做,这是可能的。