DynamicBinder 2.2.0
dotnet add package DynamicBinder --version 2.2.0
NuGet\Install-Package DynamicBinder -Version 2.2.0
<PackageReference Include="DynamicBinder" Version="2.2.0" />
paket add DynamicBinder --version 2.2.0
#r "nuget: DynamicBinder, 2.2.0"
// Install DynamicBinder as a Cake Addin #addin nuget:?package=DynamicBinder&version=2.2.0 // Install DynamicBinder as a Cake Tool #tool nuget:?package=DynamicBinder&version=2.2.0
DynamicBinder and LateBinder
What's this?
This is the class library for .NET.
This library allows you dynamic access to object methods, properties, and fields using the reflection technology of .NET, regardless of whether they are private members.
You can access both objects' instance members and classes' static members by name that specified string argument at runtime, not compile-time, or C# 4.0 "dynamic" syntax.
How to install?
You can install this library via NuGet.
> dotnet add package DynamicBinder
Usage - C# "dynamic" syntax
Create instance
After importing (opening) namespace Toolbelt
, you can use DynamicBinder.CreateInstance<T>(...)
and DynamicBinder.CreateInstance(Type t, ...)
static method to instantiate any objects with any constructors, regardless of constructor's access level (public, internal, protected, private).
Those methods return an instantiated object wrapped with the DynamicBinder
object as a dynamic
type.
using Toolbelt;
...
// 👇 The type of the "dynamicObj" is the "dynamic" type.
// In this case, the "dynamicObj" is instantiated by the constructor, which has two arguments.
// It can be instantiated even if the constructor is private.
var dynamicObj = DynamicBinder.CreateInstance<MyClass>(arg1, arg2);
// And it can be invoked its instance methods, regardless of its access level.
var retval = (int)dynamicObj.PrivateMethodName(arg3, arg4);
...
Access to instance members
After importing (opening) namespace Toolbelt.DynamicBinderExtension
, you can use ToDynamic()
extension method that returned C #4.0 dynamic
type at any object.
using Toolbelt.DynamicBinderExtension;
...
var obj = new MyClass();
...
// Call an instance method.
// (You can pass ref & out arguments.)
var retval = (int)obj.ToDynamic().MethodName(arg1, ref arg2, out int arg3);
// Get or set an instance property.
var value = (int)obj.ToDynamic().PropName;
obj.ToDynamic().PropName = newValue;
// Get or set an instance field.
var value = (int)obj.ToDynamic().FieldName;
obj.ToDynamic().FieldName = newValue;
Access to static members
After importing (opening) namespace Toolbelt
, you can use DynamicBinder.Create<T>()
and DynamicBinder.Create(Type t)
static method that returned C #4.0 dynamic
type.
using Toolbelt;
...
var binder = DynamicBinder.Create(typeof(Foo));
// Call a static method.
// (You can pass ref & out arguments.)
var retval = (int)binder.MethodName(arg1, ref arg2, out int arg3);
// Get or set a static property.
var value = (int)binder.PropName;
binder.PropName = newValue;
// Get or set a static field.
var value = (int)binder.FieldName;
binder.FieldName = newValue;
NOTICE: Retrieving a type information of the returned value from the method calling
Retrieving a type information of the return value from the method calling
The following test code will fail.
object bar = foo.ToDynamic().GetBarObject();
// 👇 It will report "actual is `DynamicBinder`" !
Assert.AreEqual("BarClass", bar.GetType().Name);
You should rewrite the above test code as follows.
// Extract a `DynamicBinder` object from the C# dynamic object by casting with `as`.
var retval = foo.ToDynamic().GetBarObject() as DynamicBinder;
// The `DynamicBinder` class exposes the `Object` property to access the bound target object.
Assert.AreEqual("BarClass", retval.Object.GetType().Name); // Green. Pass!
Of course, if you have the right type information, those test codes can be rewritten as the following:
var bar = (BarClass)foo.ToDynamic().GetBarObject();
Assert.AreEqual("BarClass", bar.GetType().Name); // Green. Pass!
Usage - Late bind syntax
Create instance
After importing (opening) namespace Toolbelt
, you can use LateBinder.CreateInstance<T>(...)
and LateBinder.CreateInstance(Type t, ...)
static method to instantiate any objects with any constructors, regardless of constructor's access level (public, internal, protected, private).
Those methods return an instantiated object wrapped with the LateBinder
type.
using Toolbelt;
...
// 👇 The type of the "dynamicObj" is the "LateBinder" type.
// In this case, the "dynamicObj" is instantiated by the constructor, which has two arguments.
// It can be instantiated even if the constructor is private.
var dynamicObj = LateBinder.CreateInstance<MyClass>(arg1, arg2);
// And it can be invoked its instance methods, regardless of its access level.
var retval = (int)dynamicObj.Call("PrivateMethodName", arg3, arg4);
...
Access to instance members
After importing (opening) namespace Toolbelt.DynamicBinderExtension
, you can use ToLateBind()
extension method that returned LateBinder
object at any object.
LateBinder
has follow members.
Call(name, params[] args)
methodProp[name]
propertyField[name]
property
using Toolbelt.DynamicBinderExtension;
...
// Call an instance method.
var retval = (int)obj.ToLateBind().Call("MethodName", arg1, arg2);
// Get or set an instance property.
var value = (int)obj.ToLateBind().Prop["PropName"];
obj.ToLateBind().Prop["PropName"] = newValue;
// Get or set an instance field.
var value = (int)obj.ToLateBind().Field["FieldName"];
obj.ToLateBind().Field["FieldName"] = newValue;
Access to static members
After importing (opening) namespace Toolbelt
, you can use LateBinder.Create<T>()
and LateBinder.Create(Type t)
static method that returned LateBinder
object.
using Toolbelt;
...
var binder = LateBinder.Create<Foo>();
// Call a static method.
var retval = (int)binder.Call("MethodName", arg1, arg2);
// Get or set a static property.
var value = (int)binder.Prop["PropName"];
binder.Prop["PropName"] = newValue;
// Get or set a static field.
var value = (int)binder.Field["FieldName"];
binder.Field["FieldName"] = newValue;
Call methods with ref
& out
arguments
To call methods with ref
& out
arguments, you can't pass those arguments to the Call
method of the late-binder directly, which is different from using the "dynamic" syntax. Instead, follow the instructions below.
// For example, if the definition of the "MethodName" static method is:
// static void MethodName(int x, ref int y, out int z){
// z = x * y;
// y = y + 1;
// }
// 1. Pack all of the arguments into an object array.
var args = new object[] { 3, 4, default(int) };
// 2. Pass it to the 2nd argument of the "Call" method.
binder.Call("MethodName", args);
// 3. Then, the "args" array will be updated.
// args[1] -> 5
// args[2] -> 12
Note
No using extension methods scenario
If you feel these extension methods are dirty, you can choose no using these extension methods.
Instead, you can use LateBinder
and DynamicBinder
class like the following code.
// Do not open namespace "Toolbelt.DynamicBinderExtension".
using Toolbelt;
...
// Instead, instantiate DynamicBinder or LateBinder objects with the "new" keyword.
dynamic dynamicBinder = new DynamicBinder(obj);
var retval = (int)dynamicBinder.MethodName(arg1, arg2);
var lateBinder = new LateBinder(obj);
var retval = (int)lateBinder.Call("MethodName", arg1, arg2);
"Reinventing the wheel"
There are no less than 50 packages about reflection & private members accessing.
But I couldn't find any packages with my favorite syntax and features 😃.
So I decided to "reinvent the wheel" by my hand.
Performance issue
In this library, DynamicBinder
and LateBinder
may be much slower because their implementation uses the reflection API directory without any technics such as caches, compiling to delegations, compiling to expressions, etc.
Therefore, I think there is plenty of room for improvement to faster, more high performance.
If you prefer, you can fork this repository and improve it.
Release Notes
Release notes are here.
Licence
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on DynamicBinder:
Repository | Stars |
---|---|
jsakamoto/Toolbelt.Blazor.I18nText
The class library that provides the ability to localize texts on your Blazor app!
|
v.2.2.0
- Enhance: Allow dynamic method call return values to be used as parameters in a method.