34 people like it.

Dynamic operator using Dynamic Language Runtime

The snippet shows a simple implementation of the dynamic operator (?) that uses Dynamic Language Runtime and the C# implementation of dynamic operations. The snippet shows how to invoke instance methods with single argument.

Implementing dynamic operator

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
// Rreference C# implementation of dynamic operations
#r "Microsoft.CSharp.dll"
open System
open System.Runtime.CompilerServices
open Microsoft.CSharp.RuntimeBinder

// Simple implementation of ? operator that works for instance
// method calls that take a single argument and return some result
let (?) (inst:obj) name (arg:'T) : 'R =
  // TODO: For efficient implementation, consider caching of call sites 
  // Create dynamic call site for converting result to type 'R
  let convertSite = 
    CallSite<Func<CallSite, Object, 'R>>.Create
      (Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null))

  // Create call site for performing call to method with the given
  // name and a single parameter of type 'T
  let callSite = 
    CallSite<Func<CallSite, Object, 'T, Object>>.Create
      (Binder.InvokeMember
        ( CSharpBinderFlags.None, name, null, null, 
          [| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |]))

  // Run the method call using second call site and then 
  // convert the result to the specified type using first call site
  convertSite.Target.Invoke
    (convertSite, callSite.Target.Invoke(callSite, inst, arg))

Example of using the operator

1: 
2: 
3: 
// Dynamically invoke 'Next' method of 'Random' type
let o = box (new Random())
let a : int = o?Next(10)
namespace System
namespace System.Runtime
namespace System.Runtime.CompilerServices
namespace Microsoft
namespace Microsoft.CSharp
namespace Microsoft.CSharp.RuntimeBinder
val inst : obj
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val name : string
val arg : 'T
val convertSite : CallSite<Func<CallSite,Object,'R>>
Multiple items
type CallSite =
  member Binder : CallSiteBinder
  static member Create : delegateType:Type * binder:CallSiteBinder -> CallSite

Full name: System.Runtime.CompilerServices.CallSite

--------------------
type CallSite<'T (requires reference type)> =
  inherit CallSite
  val Target : 'T
  member Update : 'T
  static member Create : binder:CallSiteBinder -> CallSite<'T>

Full name: System.Runtime.CompilerServices.CallSite<_>
Multiple items
type Func<'TResult> =
  delegate of unit -> 'TResult

Full name: System.Func<_>

--------------------
type Func<'T,'TResult> =
  delegate of 'T -> 'TResult

Full name: System.Func<_,_>

--------------------
type Func<'T1,'T2,'TResult> =
  delegate of 'T1 * 'T2 -> 'TResult

Full name: System.Func<_,_,_>

--------------------
type Func<'T1,'T2,'T3,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 -> 'TResult

Full name: System.Func<_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 -> 'TResult

Full name: System.Func<_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'TResult

Full name: System.Func<_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>

--------------------
type Func<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15,'T16,'TResult> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> 'TResult

Full name: System.Func<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>
Multiple items
type Object =
  new : unit -> obj
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member GetType : unit -> Type
  member ToString : unit -> string
  static member Equals : objA:obj * objB:obj -> bool
  static member ReferenceEquals : objA:obj * objB:obj -> bool

Full name: System.Object

--------------------
Object() : unit
type Binder =
  static member BinaryOperation : flags:CSharpBinderFlags * operation:ExpressionType * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member Convert : flags:CSharpBinderFlags * type:Type * context:Type -> CallSiteBinder
  static member GetIndex : flags:CSharpBinderFlags * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member GetMember : flags:CSharpBinderFlags * name:string * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member Invoke : flags:CSharpBinderFlags * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member InvokeConstructor : flags:CSharpBinderFlags * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member InvokeMember : flags:CSharpBinderFlags * name:string * typeArguments:IEnumerable<Type> * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member IsEvent : flags:CSharpBinderFlags * name:string * context:Type -> CallSiteBinder
  static member SetIndex : flags:CSharpBinderFlags * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  static member SetMember : flags:CSharpBinderFlags * name:string * context:Type * argumentInfo:IEnumerable<CSharpArgumentInfo> -> CallSiteBinder
  ...

Full name: Microsoft.CSharp.RuntimeBinder.Binder
Binder.Convert(flags: CSharpBinderFlags, type: Type, context: Type) : CallSiteBinder
type CSharpBinderFlags =
  | None = 0
  | CheckedContext = 1
  | InvokeSimpleName = 2
  | InvokeSpecialName = 4
  | BinaryOperationLogical = 8
  | ConvertExplicit = 16
  | ConvertArrayIndex = 32
  | ResultIndexed = 64
  | ValueFromCompoundAssignment = 128
  | ResultDiscarded = 256

Full name: Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags
field CSharpBinderFlags.None = 0
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
val callSite : CallSite<Func<CallSite,Object,'T,Object>>
Binder.InvokeMember(flags: CSharpBinderFlags, name: string, typeArguments: Collections.Generic.IEnumerable<Type>, context: Type, argumentInfo: Collections.Generic.IEnumerable<CSharpArgumentInfo>) : CallSiteBinder
type CSharpArgumentInfo =
  static member Create : flags:CSharpArgumentInfoFlags * name:string -> CSharpArgumentInfo

Full name: Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
CSharpArgumentInfo.Create(flags: CSharpArgumentInfoFlags, name: string) : CSharpArgumentInfo
type CSharpArgumentInfoFlags =
  | None = 0
  | UseCompileTimeType = 1
  | Constant = 2
  | NamedArgument = 4
  | IsRef = 8
  | IsOut = 16
  | IsStaticType = 32

Full name: Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags
field CSharpArgumentInfoFlags.None = 0
field CallSite.Target
Func.Invoke(arg1: CallSite, arg2: Object) : 'R
Func.Invoke(arg1: CallSite, arg2: Object, arg3: 'T) : Object
val o : obj

Full name: Script.o
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
val a : int

Full name: Script.a
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Raw view Test code New version

More information

Link:http://fssnip.net/2U
Posted:13 years ago
Author:Tomas Petricek
Tags: dynamic , invoke , reflection , dlr