System.Dynamic.ExpandoObject クラス

この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。

この ExpandoObject クラスを使用すると、実行時にそのインスタンスのメンバーを追加および削除したり、これらのメンバーの値を設定および取得したりできます。 このクラスは動的バインディングをサポートしています。これにより、次のような sampleObject.sampleMember より複雑な構文ではなく、標準構文を sampleObject.GetAttribute("sampleMember")使用できます。

このクラスは ExpandoObject 、標準の動的言語ランタイム (DLR) インターフェイス IDynamicMetaObjectProviderを実装します。これにより、DLR 相互運用性モデルを ExpandoObject サポートする言語間でクラスのインスタンスを共有できます。 たとえば、C# でクラスのインスタンスを ExpandoObject 作成し、IronPython 関数に渡すことができます。 詳細については、「 動的言語ランタイムの概要 」および 「ExpandoObject の概要」を参照してください

この ExpandoObject クラスは、メンバーの取得、設定、および呼び出しを可能にする動的オブジェクトの概念の実装です。 独自の動的ディスパッチ セマンティクスを持つ型を定義する場合は、クラスを使用します DynamicObject 。 動的オブジェクトが相互運用性プロトコルにどのように参加するかを定義し、DLR 高速動的ディスパッチ キャッシュを管理する場合は、インターフェイスの独自の実装を IDynamicMetaObjectProvider 作成します。

インスタンスを作成する

C# では、クラスのExpandoObjectインスタンスに対して遅延バインディングを有効にするには、キーワード (keyword)を使用するdynamic必要があります。 詳細については、「dynamic 型の使用」を参照してください。

Visual Basic では、動的操作は遅延バインディングによってサポートされます。 詳細については、「早期バインディングと遅延バインディング (Visual Basic)」を参照してください

次のコード例は、クラスのインスタンスを作成する方法を ExpandoObject 示しています。

dynamic sampleObject = new ExpandoObject();
Dim sampleObject As Object = New ExpandoObject()

新しいメンバーの追加

プロパティ、メソッド、およびイベントをクラスのインスタンスに ExpandoObject 追加できます。

次のコード例は、クラスのインスタンスに新しいプロパティを追加する方法を ExpandoObject 示しています。

sampleObject.test = "Dynamic Property";
Console.WriteLine(sampleObject.test);
Console.WriteLine(sampleObject.test.GetType());
// This code example produces the following output:
// Dynamic Property
// System.String
sampleObject.Test = "Dynamic Property"
Console.WriteLine(sampleObject.test)
Console.WriteLine(sampleObject.test.GetType())
' This code example produces the following output:
' Dynamic Property
' System.String

メソッドはデリゲートとして格納されるラムダ式を表し、必要に応じて呼び出すことができます。 次のコード例では、動的プロパティの値をインクリメントするメソッドを追加する方法を示します。

sampleObject.number = 10;
sampleObject.Increment = (Action)(() => { sampleObject.number++; });

// Before calling the Increment method.
Console.WriteLine(sampleObject.number);

sampleObject.Increment();

// After calling the Increment method.
Console.WriteLine(sampleObject.number);
// This code example produces the following output:
// 10
// 11
sampleObject.Number = 10
sampleObject.Increment = Function() sampleObject.Number + 1
' Before calling the Increment method.
Console.WriteLine(sampleObject.number)

sampleObject.Increment.Invoke()

' After calling the Increment method.
Console.WriteLine(sampleObject.number)
' This code example produces the following output:
' 10
' 11

次のコード例は、クラスのインスタンスにイベントを追加する方法を ExpandoObject 示しています。

class Program
{
    static void Main(string[] args)
    {
        dynamic sampleObject = new ExpandoObject();

        // Create a new event and initialize it with null.
        sampleObject.sampleEvent = null;

        // Add an event handler.
        sampleObject.sampleEvent += new EventHandler(SampleHandler);

        // Raise an event for testing purposes.
        sampleObject.sampleEvent(sampleObject, new EventArgs());
   }

    // Event handler.
    static void SampleHandler(object sender, EventArgs e)
    {
        Console.WriteLine("SampleHandler for {0} event", sender);
    }
}
// This code example produces the following output:
// SampleHandler for System.Dynamic.ExpandoObject event.
Module Module1

Sub Main()
    Dim sampleObject As Object = New ExpandoObject()

    ' Create a new event and initialize it with null.
    sampleObject.sampleEvent = Nothing

    ' Add an event handler.
    Dim handler As EventHandler = AddressOf SampleHandler
    sampleObject.sampleEvent =
        [Delegate].Combine(sampleObject.sampleEvent, handler)

    ' Raise an event for testing purposes.
    sampleObject.sampleEvent.Invoke(sampleObject, New EventArgs())

End Sub

' Event handler.
Sub SampleHandler(ByVal sender As Object, ByVal e As EventArgs)
    Console.WriteLine("SampleHandler for {0} event", sender)
End Sub

' This code example produces the following output:
' SampleHandler for System.Dynamic.ExpandoObject event.

End Module

パラメーターとして渡す

クラスのインスタンスを ExpandoObject パラメーターとして渡すことができます。 これらのインスタンスは、C# では動的オブジェクトとして扱われ、Visual Basic では遅延バインド オブジェクトとして扱われることに注意してください。 つまり、オブジェクト メンバーの IntelliSense が存在せず、存在しないメンバーを呼び出したときにコンパイラ エラーが発生することはありません。 存在しないメンバーを呼び出すと、例外が発生します。

次のコード例は、メソッドを作成して使用してプロパティの名前と値を出力する方法を示しています。

class Program
{
    static void Main(string[] args)
    {
        dynamic employee, manager;

        employee = new ExpandoObject();
        employee.Name = "John Smith";
        employee.Age = 33;

        manager = new ExpandoObject();
        manager.Name = "Allison Brown";
        manager.Age = 42;
        manager.TeamSize = 10;

        WritePerson(manager);
        WritePerson(employee);
    }
    private static void WritePerson(dynamic person)
    {
        Console.WriteLine("{0} is {1} years old.",
                          person.Name, person.Age);
        // The following statement causes an exception
        // if you pass the employee object.
        // Console.WriteLine("Manages {0} people", person.TeamSize);
    }
}
// This code example produces the following output:
// John Smith is 33 years old.
// Allison Brown is 42 years old.
Sub Main()
    Dim employee, manager As Object

    employee = New ExpandoObject()
    employee.Name = "John Smith"
    employee.Age = 33

    manager = New ExpandoObject()
    manager.Name = "Allison Brown"
    manager.Age = 42
    manager.TeamSize = 10

    WritePerson(manager)
    WritePerson(employee)
End Sub

Private Sub WritePerson(ByVal person As Object)

    Console.WriteLine("{0} is {1} years old.",
                      person.Name, person.Age)
    ' The following statement causes an exception
    ' if you pass the employee object.
    ' Console.WriteLine("Manages {0} people", person.TeamSize)

End Sub

メンバーの列挙と削除

ExpandoObject クラスは、IDictionary<String, Object> インターフェイスを実装します。 これにより、実行時にクラスのインスタンスに追加されたメンバーの ExpandoObject 列挙が有効になります。 これは、インスタンスのメンバーがコンパイル時にわからない場合に役立ちます。

次のコード例は、クラスの ExpandoObject インスタンスをインターフェイスに IDictionary<TKey,TValue> キャストし、インスタンスのメンバーを列挙する方法を示しています。

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;

foreach (var property in (IDictionary<String, Object>)employee)
{
    Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33
Dim employee As Object = New ExpandoObject()
employee.Name = "John Smith"
employee.Age = 33
For Each member In CType(employee, IDictionary(Of String, Object))
    Console.WriteLine(member.Key & ": " & member.Value)
Next
' This code example produces the following output:
' Name: John Smith
' Age: 33

メンバーを削除するための構文がない言語 (C# や Visual Basic など) では、インターフェイスにインスタンスを暗黙的にキャストし、そのメンバーをキーと値のExpandoObjectIDictionary<String, Object>ペアとして削除することで、メンバーを削除できます。 これを次の例に示します。

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");
Dim employee As Object = New ExpandoObject()
employee.Name = "John Smith"
CType(employee, IDictionary(Of String, Object)).Remove("Name")

プロパティの変更の通知を受信する

このクラスは ExpandoObject インターフェイスを INotifyPropertyChanged 実装し、メンバーが PropertyChanged 追加、削除、または変更されたときにイベントを発生させることができます。 これにより、Windows Presentation Foundation (WPF) データ バインディングや、オブジェクト コンテンツの変更に関する通知を必要とするその他の環境とのクラス統合が可能 ExpandoObject になります。

次のコード例は、イベントのイベント ハンドラーを作成する方法を PropertyChanged 示しています。

// Add "using System.ComponentModel;" line
// to the beginning of the file.
class Program
{
    static void Test()
    {
        dynamic employee = new ExpandoObject();
        ((INotifyPropertyChanged)employee).PropertyChanged +=
            new PropertyChangedEventHandler(HandlePropertyChanges);
        employee.Name = "John Smith";
    }

    private static void HandlePropertyChanges(
        object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine("{0} has changed.", e.PropertyName);
    }
}
' Add "Imports System.ComponentModel" line 
' to the beginning of the file.
Sub Main()
    Dim employee As Object = New ExpandoObject
    AddHandler CType(
        employee, INotifyPropertyChanged).PropertyChanged,
        AddressOf HandlePropertyChanges
    employee.Name = "John Smith"
End Sub

Private Sub HandlePropertyChanges(
       ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
    Console.WriteLine("{0} has changed.", e.PropertyName)
End Sub