Skip to content

UsageReallyLateBinding

Jay Tuley edited this page Mar 19, 2018 · 6 revisions

Introduction

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

Dynamitey 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.5, older versions tested higher relative performance, but something was artificially slowing down reflection, now everything is equal or faster, but if you are interested in performance rather than just supporting reflection of dynamic objects, look into Open Source Projects FasterReflect or Fast-Member instead.

Basic

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

Given a target implicitly or explicitly convert to type.

Example:

    var variable =Dynamic.InvokeConvert(target, typeof(int));
    //Language Equivalent
    int variable = target;

Example:

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

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

Given a type invoke constructor with args.

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

Example:

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

dynamic Dynamic.InvokeGet(object target, String_Or_InvokeMemberName name)

Given a target and a property name get the value.

Example:

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

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

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

Example:

    Dynamic.InvokeSet(target, "InputEncoding", Encoding.ASCII);
    //Language Equivalent
    target.InputEncoding = Encoding.ASCII;

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

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

Example:

    var variable = Dynamic.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.

Example:

    Dynamic.InvokeSetIndex(target,3,"foo");
    //Language Equivalent
    target[3]="foo";

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.

Example:

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

void 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.

Example:

   Dynamic.InvokeMemberAction(list, "Reverse")
   //Language Equivalent
   list.Reverse();

dynamic Invoke(object target, params object[] args)###

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.

Example:

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

void InvokeAction(object target, params object[] args)###

Same as Dynamic.Invoke however is necessary when the result needs to be discarded (i.e. void).

Example:

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

dynamic InvokeGetChain(object target, string propertyChain)

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

Example:

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

dynamic InvokeSetChain(object target, string propertyChain)

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

dynamic InvokeSetAll(object target, ...)

Set several properties at once, either by passing in an anonymous 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)###

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)

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)

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.

Advanced

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 = Dynamic.InvokeMember(tTarget, "MyMethod", arg("two", tValue2), arg("one", tValue1));

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 = Dynamic.InvokeMember(tTarget, name("MyMethod", new[]{typeof(bool)}), tValue);

Static Methods/Properties

         var staticContext = InvokeContext.CreateStatic ;

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

Unknown Delegates

By using Dynamitey 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: 3-5x 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 Dynamitey'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,
                                            new[]
                                                {
                                                    Info.Create(
                                                        InfoFlags.None, null),
                                                    Info.Create(
                                                        InfoFlags.IsOut |
                                                        InfoFlags.UseCompileTimeType, null)
                                                });


            var tSite = Dynamitey.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 1x 2.2x
Set 1x 3x
Constructor * 2x 4x
InvokeMember 1x 2x
InvokeAction 1x 1.7x

* 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.

Clone this wiki locally