組み込みの参照型 (C# リファレンス)

C# には複数の組み込み参照型があります。 それらには、.NET ライブラリでの型に対するシノニムであるキーワードまたは演算子があります。

オブジェクトの型

object 型は .NET での System.Object の別名です。 C# の統一型システムでは、すべての型 (定義済み、ユーザー定義、参照型、および値の型) が、直接または間接的に System.Object を継承します。 object 型の変数には、任意の型の値を割り当てることができます。 すべての object 変数には、リテラル null を使って既定値を割り当てることができます。 値型の変数が object に変換されることを、ボックス化 されると言います。 object 型の変数が値型に変換されることを、ボックス化解除 されると言います。 詳細については、「ボックス化とボックス化解除」を参照してください。

文字列型

string 型は、0 個以上の Unicode 文字のシーケンスを表します。 string は .NET の System.String の別名です。

string は参照型ですが、等値演算子 == および != は、string オブジェクトの参照ではなく、値を比較するように定義されています。 これにより、文字列が等しいかを直感的にテストできます。 次に例を示します。

string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));

文字列の内容が等しいので、"True"、"False" の順に表示されますが、a および b は同じ文字列インスタンスを参照しません。

+ 演算子では、文字列が連結されます。

string a = "good " + "morning";

これは、"good morning" を含む文字列オブジェクトを作成します。

文字列は "変更不可" です。文字列オブジェクトの作成後、そのコンテンツを変更することはできません。構文では変更可能に見えても、変更不可です。 たとえば、このコードを作成すると、コンパイラによって新しい文字列オブジェクトを格納する新しいシーケンス オブジェクトが生成され、その新しいオブジェクトが b に割り当てられます。 b に割り当てられたメモリは (文字列 "h" が含まれている場合)、ガベージ コレクションの対象になります。

string b = "h";
b += "ello";

[] 演算子は、文字列の各文字への読み取り専用アクセスに使用できます。 有効なインデックス値は 0 から始まり、文字列の長さ未満である必要があります。

string str = "test";
char x = str[2];  // x = 's';

同様に、[] 演算子を使って文字列内の各文字を反復処理することもできます。

string str = "test";

for (int i = 0; i < str.Length; i++)
{
  Console.Write(str[i] + " ");
}
// Output: t e s t

文字列リテラルは string 型であり、二重引用符で囲む形式と、@ 付きの二重引用符で囲む形式の 2 種類があります。 二重引用符で囲む場合は、リテラル文字列の前後に二重引用符 (") を付けます。

"good morning"  // a string literal

リテラル文字列には、任意の文字リテラルを含めることができます。 これにはエスケープ シーケンスが含まれます。 次の例では、円記号にエスケープ シーケンス \\、文字 f に \u0066、改行に \n を使用しています。

string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
//  F

注意

エスケープ コード \udddd (dddd は 4 桁の数字) は、Unicode 文字 U +dddd を表します。 8 桁の Unicode エスケープ コード \Udddddddd も認識できます。

verbatim 文字列リテラルの場合は、先頭に @ を付け、さらに前後に二重引用符を付けます。 次に例を示します。

@"good morning"  // a string literal

verbatim 文字列の場合の利点は、エスケープ シーケンスが "処理されない" ため、たとえば、完全修飾 Windows ファイル名が書きやすくなることです。

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

@-quoted 文字列に二重引用符を含めるには、二重引用符を二重にします。

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

デリゲート型

デリゲート型の宣言は、メソッド シグネチャに似ています。 戻り値 1 つのほか、任意の型のパラメーターをいくつでも指定することができます。

public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);

.NET では、System.Action 型と System.Func 型により、多くの一般的なデリゲートに対するジェネリック定義が提供されます。 おそらく、新しいカスタム デリゲート型を定義する必要はありません。 代わりに、提供されたジェネリック型のインスタンス化を作成できます。

delegate は、名前付きメソッドまたは匿名メソッドをカプセル化することができる参照型です。 デリゲートは C++ の関数ポインターに似ていますが、タイプ セーフであり安全です。 デリゲートの使い方については、デリゲート汎用デリゲートに関するページを参照してください。 デリゲートはイベントの土台となる働きをします。 デリゲートは名前付きメソッドまたは匿名メソッドに関連付けることによって、インスタンス化することができます。

デリゲートは、適合する入力パラメーターと戻り値の型を持ったメソッドまたはラムダ式でインスタンス化する必要があります。 メソッドのシグネチャでどの程度の変性が許容されるかについて詳しくは、デリゲートの変性に関するページを参照してください。 匿名メソッドで使用する場合は、デリゲートとそれに関連付けるコードとを一緒に宣言します。

バリアント変換が原因で実行時に関係するデリゲート型が異なる場合、デリゲートの組み合わせと削除はランタイム例外で失敗します。 次に示すのは、失敗する状況の例です。

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Valid due to implicit reference conversion of
// objectAction to Action<string>, but may fail
// at runtime.
Action<string> combination = stringAction + objectAction;

新しいデリゲート オブジェクトを作成することにより、適切なランタイム型でデリゲートを作成できます。 次に示すのは、この回避策を前の例に適用する方法です。

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Creates a new delegate instance with a runtime type of Action<string>.
Action<string> wrappedObjectAction = new Action<string>(objectAction);

// The two Action<string> delegate instances can now be combined.
Action<string> combination = stringAction + wrappedObjectAction;

C# 9 以降では、同様の構文を使用する "関数ポインター" を宣言できます。 関数ポインターでは、デリゲート型をインスタンス化して仮想 Invoke メソッドを呼び出す代わりに、calli 命令を使用します。

dynamic 型

dynamic 型は、変数およびそのメンバーに対する参照の使用が、コンパイル時の型チェックをバイパスすることを示します。 代わりに、演算は実行時に解決されます。 dynamic 型により、Office オートメーション API などの COM API、IronPython ライブラリなどの動的 API、および HTML ドキュメント オブジェクト モデル (DOM: Document Object Model) へのアクセスが容易になります。

ほとんどの環境で、dynamic 型は object 型のように動作します。 具体的には、null 以外の任意の式を dynamic 型に変換できます。 dynamic 型は object と異なり、dynamic 型の式を含む演算はコンパイラによって解決または型チェックされません。 コンパイラは演算に関する情報をまとめてパッケージ化します。その情報が後で実行時に演算を評価するために使用されます。 このプロセスの過程で、dynamic 型の変数は object 型の変数にコンパイルされます。 そのため、dynamic 型はコンパイル時にのみ存在し、実行時には存在しません。

dynamic 型の変数と object 型の変数の違いを次に示します。 コンパイル時に各変数の型を確認するには、WriteLine ステートメントの dyn または obj にマウス ポインターを置きます。 IntelliSense が使用可能なエディターに、次のコードをコピーします。 IntelliSense 機能によって、dyn には dynamicobj には object が表示されます。

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

WriteLine ステートメントは dyn および obj の実行時の型を表示します。 その時点では、両方が同じ整数型を持ちます。 次の出力が生成されます。

System.Int32
System.Int32

コンパイル時の dynobj の違いを確認するには、前の例の宣言と WriteLine ステートメントの間に次の 2 行を追加します。

dyn = dyn + 3;
obj = obj + 3;

obj + 3 に整数およびオブジェクトを追加しようとしたことに対してコンパイル エラーが報告されます。 ただし、dyn + 3 に関するエラーは報告されません。 dyn を含む式はコンパイル時にはチェックされません。これは、dyn の型が dynamic であるためです。

さまざまな宣言で dynamic を使用する例を次に示します。 また、Main メソッドで、コンパイル時の型チェックと実行時の型チェックの違いを確認できます。

using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // The following line causes a compiler error because exampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to exampleMethod
            // with two arguments does not produce an error at compile time.
            // However, it does cause a run-time error.
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable

関連項目