-
Notifications
You must be signed in to change notification settings - Fork 44
UsageReallyLateBinding
#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.0 and Silverlight 4.0 using ImpromptuInterface from which this code is based and 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
#Basic#
Given a target implicitly or explicitly convert to type.
Example:
var variable =Dynamic.InvokeConvert(target, tyepof(int));
//Language Equivalent
int variable = target;
Example:
var variable =Dynamic.InvokeConvert(target, tyepof(int),explicit:true);
//Language Equivalent
var variable =(int)target;
Given a type invoke constructor with args.
-
Speed: 5x 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);
Given a target and a property name get the value.
- Speed: 4x faster than reflection.
Example:
var variable = Dynamic.InvokeGet(target, "InputEncoding");
//Language Equivalent
var variable = target.InputEncoding;
Given a target and a property name set the value. returns value.
- Speed: 3x faster than reflection.
Example:
Dynamic.InvokeSet(target,"InputEncoding",Encoding.ASCII);
//Language Equivalent
target.InputEncoding = Encoding.ASCII;
Given a target and index(es) get the value.
Example:
var variable = Dynamic.InvokeGetIndex(target,3);
//Language Equivalent
var variable =target[3];
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.
- Speed: 2x faster than reflection.
Example:
var relUri = Dynamic.InvokeMember(baseUri, "MakeRelativeUri", absUri);
//Language Equivalent
var relUri = baseUri.MakeRelative(absUri)
Given a target and a method name of a method that returns void, call it.
- Speed: 4x faster than reflection.
Example:
Dynamic.InvokeMemberAction(list, "Reverse")
//Language Equivalent
list.Reverse();
(>= 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.
Example:
var result = Dynamic.Invoke(func, 3, 2);
//Language Equivalent
var result = func(3,2);
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);
(>= Core v5.5) 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;
Works like InvokeSet
however, allows you to pass in a chain of properties ("Prop.NestedProp.NestedNestProp"
) and set the final property.
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.
Use several runtime API's not just the DLR to try to and convert to a type.
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)
Uses the dlr to perform a unary operation. (ExpressionType.Not, ExpressionType.Negate, ExpressionType.Decrement, ExpressionType.Increment)
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 = 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);
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: 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 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 | 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.