Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Jay Tuley edited this page · 3 revisions


Really late binding is describing calling a member when you only know the name at runtime(i.e. a string of the member name).

Impromptu Interfaces has several static methods for simplifying and efficiently doing really late binding using the dlr on any type of object static or dynamic. (on static objects it invokes faster or equal to reflection depending on the action).

Note: references to relative speed of relate to .NET 4.0 and Silverlight 4.0 not Mono, either Mono's dynamic binding runs slower or maybe Mono's reflection runs faster, I'm not sure I haven't gotten code profiling to work yet on Mono 2.10 to see what's the issue


dynamic InvokeConvert(object target, Type type, bool explict =false)

Given a target implicitly or explicitly convert to type.


    var variable =Impromptu.InvokeConvert(target, tyepof(int));
    //Language Equivalent
    int variable = target;


   var variable =Impromptu.InvokeConvert(target, tyepof(int),explicit:true);
   //Language Equivalent
   var variable =(int)target;

dynamic InvokeConstructor(Type type, params object[] args)

Given a type invoke constructor with args.

  • Speed: 5x faster than Activator.CreateInstance(Type type, params object[] args)


    var variable = Impromptu.InvokeConstructor(typeof(DateTime),2012,1,1);
    //Language Equivalent
    var variable = new DateTime(2012,1,1);

dynamic Impromptu.InvokeGet(object target, String_Or_InvokeMemberName name)

Given a target and a property name get the value.

  • Speed: 4x faster than reflection.


    var variable = Impromput.InvokeGet(target, "InputEncoding");
    //Language Equivalent
    var variable = target.InputEncoding;

dynamic Impromptu.InvokeSet(object target, String_Or_InvokeMemberName name, object value)

Given a target and a property name set the value. returns value.

  • Speed: 3x faster than reflection.


    //Language Equivalent
    target.InputEncoding = Encoding.ASCII;

dynamic InvokeGetIndex(object target, params object[] indexes)

Given a target and index(es) get the value.


    var variable = Impromptu.InvokeGetIndex(target,3);
    //Language Equivalent
    var variable =target[3];

void InvokeSetIndex(object target, params object[] indexesThenValue)

Given a target and index(es) set the value.


    //Language Equivalent

dynamic Impromptu.InvokeMember(object target, String_Or_InvokeMemberName name, params object[] args)

Given a target and a method name, call it and return the result.

  • Speed: 2x faster than reflection.


  var relUri = Impromptu.InvokeMember(baseUri, "MakeRelativeUri", absUri);
   //Language Equivalent
  var relUri = baseUri.MakeRelative(absUri)

void Impromptu.InvokeMemberAction(object target, String_Or_InvokeMemberName name, params object[] args)

Given a target and a method name of a method that returns void, call it.

  • Speed: 4x faster than reflection.


   Impromptu.InvokeMemberAction(list, "Reverse")
   //Language Equivalent

dynamic Impromptu.Invoke(object target, params object[] args)

(>= Core v5.5) Given a target (delegate or invoke-able dynamic object) invokes it. Will not be as fast as FastDynamicInvoke off of the delegate, but more flexible in that it can use dynamic named arguments and invoke dynamic objects.


   var result = Impromptu.Invoke(func, 3, 2);
   //Language Equivalent
   var result = func(3,2);

void Impromptu.InvokeAction(object target, params object[] args)

(>= Core v5.5) Same as Impromptu.Invoke however is necessary when the result needs to be discarded (i.e. void).


   Impromptu.InvokeAction(action, parm1, parm2);
   //Language Equivalent
   action(parm1, parm2);

dynamic Impromptu.InvokeGetChain(object target, string propertyChain)

(>= Core v5.5) Works like InvokeGet however, allows you to pass in a chain of properties ("Prop.NestedProp.NestedNestProp") and get the final result.


   var result =Impromptu.InvokeGetChain(target, "Prop1.Prop2.Prop3");
   //Language Equivalent
   var result = target.Prop1.Prop2.Prop3;

dynamic Impromptu.InvokeSetChain(object target, string propertyChain)

(>= Core v5.5) Works like InvokeSet however, allows you to pass in a chain of properties ("Prop.NestedProp.NestedNestProp") and set the final property.

dynamic Impromput.InvokeSetAll(object target, ...)

(>= Core v5.5) Set several properties at once, either by passing in an annoymous object or dictionary as the second parameter or using multiple named parameters where the name matches the property (case sensitive). returns target.

void InvokeAddAssignMember(object target, string name, object value)

void InvokeSubtractAssignMember(object target, string name, object value)

dynamic CoerceConvert(object target, Type type)

(>= Core v6.0) Use several runtime API's not just the DLR to try to and convert to a type.

dynamic InvokeBinaryOperator(object leftArg, ExpressionType op, object rightArg)

(>= Core v6.0) Uses the dlr to perform a binary operation. (ExpressionType.Add, ExpressionType.AddAssign, ExpressionType.AndAssign, ExpressionType.Divide, ExpressionType.DivideAssign, ExpressionType.Equal, ExpressionType.ExclusiveOr, ExpressionType.ExclusiveOrAssign, ExpressionType.GreaterThan, ExpressionType.GreaterThanOrEqual, ExpressionType.LeftShift, ExpressionType.LeftShiftAssign, ExpressionType.LessThan, ExpressionType.LessThanOrEqual, ExpressionType.Modulo, ExpressionType.ModuloAssign, ExpressionType.Multiply, ExpressionType.MultiplyAssign, ExpressionType.NotEqual, ExpressionType.OrAssign, ExpressionType.RightShift, ExpressionType.RightShiftAssign, ExpressionType.Subtract, ExpressionType.SubtractAssign, ExpressionType.Or, ExpressionType.And)

dynamic InvokeUnaryOpartor(ExpressionType op, object arg)

(>= Core v6.0) Uses the dlr to perform a unary operation. (ExpressionType.Not, ExpressionType.Negate, ExpressionType.Decrement, ExpressionType.Increment)

IEnumerable<string> GetMemberNames(object target, bool dynamicOnly = false)

Get's member names of IDynamicMetaObjectProviders that provide that information & uses reflection to pool public members unless you pass true into dynamicOnly.


Named/Optional Arguments

There is a syntax for adding named argument information to the call. You wrap your arguments in an new InvokeArg(string name, value) it also has a delegate to clean up the syntax when hard coding

         var arg = InvokeArg.Create;

         var tOut = Impromptu.InvokeMember(tTarget, "MyMethod", arg("two", tValue2), arg("one", tValue1));

or using ImpromptuInterface.InvokeExt

         var tOut = Impromptu.InvokeMember(tTarget,"MyMethod", tValue2.WithArgumentName("two"), tValue1.WithArgumentName("one"));

Generic Method Type Arguments

There is a syntax for adding generic argument type parameters when you need to specify them rather than letting them be inferred by wrapping you member name in an new InvokeMemberName(string name, params Type[] genericArgs).

         var name = InvokeMemberName.Create;

         var tOut = Impromptu.InvokeMember(tTarget, name("MyMethod", new[]{typeof(bool)}), tValue);

or using ImpromptuInterface.InvokeExt

         var tOut = Impromptu.InvokeMember(tTarget,"MyMethod".WithGenericArgs(typeof(bool)), tValue);

Static Methods/Properties

         var staticContext = InvokeContext.CreateStatic ;

         var tOut = Impromptu.InvokeMember(staticContext(typeof(MyClass)), "MyMethod", tValue);

or using ImpromptuInterface.InvokeExt

         var tOut = Impromptu.InvokeMember(typeof(MyClass).WithStaticContext(),"MyMethod", tValue);

Unknown Delegates

By using ImpromptuInterface you get an extension method on Delegate, object FastDynamicInvoke(this Delegate del, params object[] args) this works exactly like the built in method DynamicInvoke except it uses the DLR for a dramatic speed increase.

  • Speed: Over 20x!!!! faster than DynamicInvoke.

Really Late binding arguments with ref/out arguments etc.

Unfortunately there's no easy way to wrap this behavior but you can still use ImpromptuInterface's plumbing so that it is cached and performed efficiently.

/// <summary>
    /// Dynamic Delegates need to return object or void, first parameter should be a CallSite, second object, followed by the expected arguments
    /// </summary>
    public delegate object DynamicTryString(CallSite callsite, object target, out string result);


           string tResult = String.Empty;

            var tPoco = new MethOutPoco();

            var tName = "Func";
            var tContext = GetType();
            var tBinder =
                Binder.InvokeMember(BinderFlags.None, tName, null, tContext,
                                                        InfoFlags.None, null),
                                                        InfoFlags.IsOut |
                                                        InfoFlags.UseCompileTimeType, null)

            var tSite = Impromptu.CreateCallSite<DynamicTryString>(tBinder, tName, tContext);

            tSite.Target.Invoke(tSite, tPoco, out tResult);

Custom Cacheable

That static Invoke methods use a hash table cache to reuse CallSites with the same signature. However you can gain significant performance if you have CallSite first and don't have to look them up in the table. There is an Invocation class which is just an object form of the invoke apis and it has a companion version CacheableInvocation that in exchange for specifying the signature, it will store CallSite with the object producing potential performance gains in loops and such.

public IEnumerable<dynamic> GetAllMethod(string methodName, object arg){

          var tCachedInvoke = new CacheableInvocation(InvocationKind.InvokeMember,methodName, argCount:1);
          return ListProperty.Select(it=>(dynamic) tCachedInvoke.Invoke(it, arg));


Potential Performance Numbers are performance relative to Reflection:

Invocation Kind Invocation CacheableInvocation
Get 4x 13x
Set 3x 15x
Constructor * 5x 11x
InvokeMember 2x 6x
InvokeAction 4x 19x

* Note that this refers to a constructor with arguments, if there are no arguments reflection is faster. However, impromptu is still faster for constructors that actually have arguments but are optional and then invoked without any.

Something went wrong with that request. Please try again.