-
Notifications
You must be signed in to change notification settings - Fork 44
UsageReallyLateBinding
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.
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;
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);
Given a target and a property name get the value.
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.
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.
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.
Example:
Dynamic.InvokeMemberAction(list, "Reverse")
//Language Equivalent
list.Reverse();
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);
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
.
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));
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);
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
.
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);
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.