私を困惑させているのは何ですか:「プライベート」であるため、派生クラスでどのように使用できますか? これ(「デフォルト名」)とはどういう意味ですか? **オブジェクトはどのようにして「デフォルト名」を名前として取得するのですか?
あなたは当惑するのは正しいです!
そのコード サンプルはデフォルト コンストラクターをまったく呼び出しません。それはプライベートであるため、リフレクションを使用せずにそれを呼び出すことはできません (派生クラスでさえありません。少なくともprotected
派生クラスがそれを呼び出す必要があります。または派生クラスは基本クラス内にネストする必要があります)。
サンプル コードでは、オブジェクトは値として "Default Name" を取得しません。
したがって、それは本のタイプミスまたはエラーです。
本が説明していることに対する正しい解決策は次のとおりです。
- デフォルトのコンストラクターを完全に省略します。
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()
メソッドの代わりにプライベート コンストラクターを使用する必要があります。
プライベート デフォルト コンストラクターのもう 1 つの用途は、型のインスタンス化をまったく防止することです (プライベート デフォルト コンストラクターを宣言するだけで、他のコンストラクターはまったく宣言しません)。
.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);
個人的には、それを含むクラスから派生するネストされたクラスを作成する必要はありませんでしたが、何らかの理由でそれを行う必要がある場合は可能です。