The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject.sampleMember instead of more complex syntax like sampleObject.GetAttribute("sampleMember").
The ExpandoObject class implements the standard Dynamic Language Runtime (DLR) interface IDynamicMetaObjectProvider, which enables you to share instances of the ExpandoObject class between languages that support the DLR interoperability model. For example, you can create an instance of the ExpandoObject class in C# and then pass it to an IronPython function. For more information, see Dynamic Language Runtime Overview and documentation on the CodePlex Web site.
The ExpandoObject class is an implementation of the dynamic object concept that enables getting, setting, and invoking members. If you want to define types that have their own dynamic dispatch semantics, use the DynamicObject class. If you want to define how dynamic objects participate in the interoperability protocol and manage DLR fast dynamic dispatch caching, create your own implementation of the IDynamicMetaObjectProvider interface.
Creating an Instance
In C#, to enable late binding for an instance of the ExpandoObject class, you must use the dynamic keyword. For more information, see Using Type dynamic (C# Programming Guide).
In Visual Basic, dynamic operations are supported by late binding. For more information, see Early and Late Binding.
The following code example demonstrates how to create an instance of the ExpandoObject class.
Dim sampleObject As Object = New ExpandoObject()
dynamic sampleObject = new ExpandoObject();
Adding New Members
The following code example demonstrates how to add a new property to an instance of the ExpandoObject class.
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
You can also add methods to instances of the ExpandoObject class. The methods represent lambda expressions that are stored as delegates, which can be invoked when they are needed. The following code example demonstrates how to add a method that increments a value of the dynamic property.
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
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
Passing As a Parameter
You can pass instances of the ExpandoObject class as parameters. Note that these instances are treated as dynamic objects in C# and late-bound objects in Visual Basic. This means that you do not have IntelliSense for object members and you do not receive compiler errors when you call non-existent members. If you call a member that does not exist, an exception occurs.
The following code example demonstrates how you can create and use a method to print the names and values of properties.
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
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.
Enumerating and Deleting Members
The ExpandoObject class implements the IDictionary<String, Object> interface. This enables enumeration of members added to the instance of the ExpandoObject class at run time. This can be useful if you do not know at compile time what members an instance might have.
The following code example shows how you can cast an instance of the ExpandoObject class to the IDictionary<(Of <(TKey, TValue>)>) interface and enumerate the instance's members.
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
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
In languages that do not have syntax for deleting members (such as C# and Visual Basic), you can delete a member by implicitly casting an instance of the ExpandoObject to the IDictionary<String, Object> interface and then deleting the member as a key/value pair. This is shown in the following example.
Dim employee As Object = New ExpandoObject()
employee.Name = "John Smith"
CType(employee, IDictionary(Of String, Object)).Remove("Age")
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");
Receiving Notifications of Property Changes
The ExpandoObject class implements the INotifyPropertyChanged interface and can raise a PropertyChanged event when a member is added, deleted, or modified. This enables ExpandoObject class integration with Windows Presentation Foundation (WPF) data binding and other environments that require notification about changes in the object content.
The following code example demonstrates how to create an event handler for the PropertyChanged event.
' 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
// 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);
}
}