3

Beginning Visual C# 2012を読んでいます。

検討:

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

本での説明: これ (「デフォルト名」) を使用して、このコンストラクターが呼び出された場合に Name が値を取得するようにしたことに注意してください。これは、このクラスを使用して新しいクラスを派生させる場合に可能です。名前フィールドに値を割り当てないと、後でエラーの原因になる可能性があるため、これは必要です。

私を困惑させているのは何ですか:「プライベート」であるため、派生クラスでどのように使用できますか? これ (「デフォルト名」) はどういう意味ですか? オブジェクトはどのようにして「デフォルト名」を名前として取得しますか?

4

3 に答える 3

9

私を困惑させているのは何ですか:「プライベート」であるため、派生クラスでどのように使用できますか? これ(「デフォルト名」)とはどういう意味ですか? **オブジェクトはどのようにして「デフォルト名」を名前として取得するのですか?

あなたは当惑するのは正しいです!

そのコード サンプルはデフォルト コンストラクターをまったく呼び出しません。それはプライベートであるため、リフレクションを使用せずにそれを呼び出すことはできません (派生クラスでさえありません。少なくともprotected派生クラスがそれを呼び出す必要があります。または派生クラスは基本クラス内にネストする必要があります)。

サンプル コードでは、オブジェクトは値として "Default Name" を取得しません。

したがって、それは本のタイプミスまたはエラーです。

本が説明していることに対する正しい解決策は次のとおりです。

  1. デフォルトのコンストラクターを完全に省略します。
  2. 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);

個人的には、それを含むクラスから派生するネストされたクラスを作成する必要はありませんでしたが、何らかの理由でそれを行う必要がある場合は可能です。

于 2013-07-07T19:05:15.037 に答える
0

プライベート コンストラクターは、ユーザーがクラスを直接インスタンス化できないことを意味します。代わりに、名前付きコンストラクタ Idiom のようなものを使用してオブジェクトを作成できます。ここでは、クラスのインスタンスを作成して返すことができる静的クラス関数があります。プライベート コンストラクターを使用して、通常シングルトン パターンで使用されるオブジェクトのインスタンスを制御できます。

プライベート コンストラクターの目的を理解するには、シングルトン パターンを読む必要があります。

于 2013-07-07T19:11:16.430 に答える