If you've got a copy of the Visual Studio 2010 CTP and you've been watching the presentations done by Anders Hejlsberg and Jim Hugunin at the Microsoft Professional Developer's Conference 2008, you may be wondering where the DynamicObject class is. It's not in the CTP. If you snoop around in the System.Scripting.Actions namespace, you'll find some of the required pieces but the actual DynamicObject class used in the demos just isn't there.
There's nothing magical about the DynamicObject class. It's a pretty simple IDynamicObject implementation that maps calls through the MetaObject for the DynamicObject as follows:
- MetaObject.GetMember => DynamicObject.GetMember
- MetaObject.SetMember => DynamicObject.SetMember
- MetaObject.Invoke => DynamicObject.Invoke
- MetaObject.Call => DynamicObject.InvokeMember
Of couse, these little "dispatchers" just set up the expression tree tests and targets as Jim described in his talk. Curt Hagenlocher was kind enough to provide a copy of the DynamicObject source code which can be found here. Thanks, Curt! I've also included the source code here, too. If you include this class in your project, the VS2010 CTP demos that Anders and Jim showed at PDC2008 will work just fine.
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Microsoft Public License. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Microsoft Public License, please send an email to
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Scripting.Actions;
namespace System.Dynamic {
public class DynamicObject : IDynamicObject {
public virtual object GetMember(GetMemberAction info) {
throw new MissingMemberException("Dynamic", info.Name);
}
public virtual void SetMember(SetMemberAction info, object value) {
throw new MissingMemberException("Dynamic", info.Name);
}
public virtual object Invoke(InvokeAction info, object[] arguments) {
throw new NotImplementedException("Invoke");
}
public virtual object InvokeMember(CallAction info, object[] arguments) {
throw new NotImplementedException("InvokeMember");
}
public MetaObject GetMetaObject(Expression parameter) {
return new DynamicMetaObject(this, parameter);
}
class DynamicMetaObject : MetaObject {
public DynamicMetaObject(DynamicObject v, Expression e) : base(e, Restrictions.Empty, v) { }
public override MetaObject GetMember(GetMemberAction info, MetaObject[] args) {
var x = this.Expression;
var test = Expression.TypeIs(x, typeof(DynamicObject));
var target = Expression.Call(
Expression.Convert(x, typeof(DynamicObject)),
typeof(DynamicObject).GetMethod("GetMember"),
Expression.Constant(info));
return new MetaObject(target, Restrictions.ExpressionRestriction(test));
}
public override MetaObject SetMember(SetMemberAction info, MetaObject[] args) {
var x = this.Expression;
var y = args[1].Expression;
var test = Expression.TypeIs(x, typeof(DynamicObject));
var target = Expression.Call(
Expression.Convert(x, typeof(DynamicObject)),
typeof(DynamicObject).GetMethod("SetMember"),
Expression.Constant(info),
Expression.ConvertHelper(y, typeof(object)));
return new MetaObject(target, Restrictions.ExpressionRestriction(test));
}
public override MetaObject Invoke(InvokeAction action, MetaObject[] args) {
var x = this.Expression;
var test = Expression.TypeIs(x, typeof(DynamicObject));
var inits = new Expression[args.Length - 1];
for (int i = 0; i < inits.Length; i++) {
inits[i] = Expression.ConvertHelper(args[i + 1].Expression, typeof(object));
}
var argsArray = Expression.NewArrayHelper(typeof(object), inits);
var target = Expression.Call(
Expression.Convert(x, typeof(DynamicObject)),
typeof(DynamicObject).GetMethod("Invoke"),
Expression.Constant(action), argsArray);
return new MetaObject(target, Restrictions.ExpressionRestriction(test));
}
public override MetaObject Call(CallAction action, MetaObject[] args) {
var x = this.Expression;
var test = Expression.TypeIs(x, typeof(DynamicObject));
var inits = new Expression[args.Length - 1];
for (int i = 0; i < inits.Length; i++) {
inits[i] = Expression.ConvertHelper(args[i + 1].Expression, typeof(object));
}
var argsArray = Expression.NewArrayHelper(typeof(object), inits);
var target = Expression.Call(
Expression.Convert(x, typeof(DynamicObject)),
typeof(DynamicObject).GetMethod("InvokeMember"),
Expression.Constant(action), argsArray);
return new MetaObject(target, Restrictions.ExpressionRestriction(test));
}
}
}
}