.NET Bridge allows Python and R to access .NET libraries, with the .NET library running either locally or on a remote machine. From R or Python one can:
create .NET objects
call member functions
call class functions (i.e. static members)
access and set properties
access indexing members
Two packages are provided, in addition to the .NET codebase:
matrices (with optional named row and column indices)
Needless to say, the framework supports code written in C#, F#, or other .NET languages. Access to types is made through reflection and does not need to be language aware.
How It Works
The R or Python packages communicate with the .NET side through simple client / server interactions. Your .NET libraries are loaded by a runner CLRServer.exe that provides a TCP-based API, giving full visibility into your library(ies).
On first use from R or Python, the package will start the .NET bridge server (or alternatively connect to an existing server). If the server is started from within VisualStudio, Xamarin Studio, or other tool, can be run in debug mode, so that you can debug your libraries as they are called from R or Python.
When a method is first called the code looks for all methods in a class that may match based on name and number of arguments and then picks the method from that subset with the closest convertible signature. The argument set need not be a perfect match in terms of types provided that the types can be reasonably converted. For example strings will be converted to enum values if a given signature requires an enum, integers can be converted to floating point, double[] arrays can be applied to double[] or Vector, etc. These signatures are cached so that subsequent calls avoid scanning.
For example if a class has 2 overloaded public methods "F":
public double F (double x, Vector<double> series)
public double F (Direction dir, Vector<double> series)
where Direction is enum Direction { Up, Down }. If the object is called from R or python as:
obj.F ('Up', [0.1, 0.2, 3.0, 3.1, 3.2])
the second method would be chosen given that 'Up' is convertible to Direction.Up and the numeric array is convertible to Vector<double>.
Initialization
The .NET bridge server (CLRServer.exe) will not have access to your code unless you indicate a DLL to be loaded. One needs to instruct the server to load a dll or dlls from your environment. There are a number of ways to do this:
run CLRServer.exe -dll on the command line
run CLRServer.exe -dll in your favorite IDE (particularly useful for debugging)
run from within R or Python
From within R one has two options. The first approach is to set an environment variable either within the R session or externally:
## set environment variable
Sys.setenv(rDotNet_DLL="~/Dev/mymodels.dll") OR
Sys.setenv(RDOTNET_DLL="~/Dev/mymodels.dll")
## load package
require(rDotNet)
## create an object and call a methodobj<- .cnew ("NormalDistribution1D", 0.0, 1.0)
obj$F (0.1)
The second approch is to explicitly call the rDotNet initialization function:
require(rDotNet)
## initialize
.cinit(dlls="~/Dev/mymodels.dll")
## create an object and call a methodobj<- .cnew ("NormalDistribution1D", 0.0, 1.0)
obj$F (0.1)
In python, the CLR is initialized using the CLRApi constructor. .NET object can then be created and interacted with directly:
clr=CLRApi (dll="~/Dev/mymodels.dll")
## create an object and call a methodobj<-clr.new ("NormalDistribution1D", 0.0, 1.0)
obj.F (0.1)
Example
Assuming the following (contrived) .NET classes:
namespacecom.stg.dummy
{
classPoint (double X, double Y);
class Circle
{
Circle (doubleradius)
{
_radius=radius;
}
publicdoubleRadius
{ get { return_radius; } set { _radius=value; } }
publicdoubleArea
{ get { returnMath.PI*_radius*_radius; } }
...
// function returning list of objectspublicList<Point> PointsFor1 (intnpoints)
{
varincr=2.0*Math.PI/ (double)npoints;
varlist=newList<Point>[);
for (inti=0 ; i<npoints ; i++)
{
vartheta= (double)i*incr;
varx=_radius*Math.cos(theta);
vary=_radius*Math.sin(theta);
list.Add (newPoint(x,y));
}
returnlist;
}
// function returning array of objectspublicPoint[] PointsFor2 (intnpoints)
{
returnPointsFor(npoints).ToArray();
}
}
}
The R api uses the $ syntax to reference members much like other R object approaches. Here is how we could call the above from R:
## create circle objectcircle<- .cnew("com.stg.dummy.Circle", 10.0)
## get the list of points backpointlist<-circle$PointsFor1 (100)
## dereference one of the point objectspoint<-pointlist[2]
## or do it all in one gopoint<-circle$PointsFor1 (100)[3]
## getting a propertycircle$Get("Area")
## setting a propertycircle$Set("Radius, 20)
The python API provides .NET objects as first class citizens in Python as proxy objects. One can interact with these proxy objects with normal python syntax. Here is how we could call the above from python:
clr=CLRApi.get()
## create circle objectcircle=clr.new("com.stg.dummy.Circle", 10.0)
## get the list of points backpointlist=circle.PointsFor1 (100)
## dereference one of the point objectspoint=pointlist[2]
## or do it all in one gopoint=circle.PointsFor1 (100)[3]
## getting a propertycircle.Area## setting a propertycircle.Radius=20
Repository Locations
The R and Python packages were uploaded and approved by CRAN and PyPi respectively. The packages reside at:
tr8dr/.Net-Bridge
.Net Bridge
.NET Bridge allows Python and R to access .NET libraries, with the .NET library running either locally or on a remote machine. From R or Python one can:
Two packages are provided, in addition to the .NET codebase:
The following data types in arguments are supported:
Needless to say, the framework supports code written in C#, F#, or other .NET languages. Access to types is made through reflection and does not need to be language aware.
How It Works
The R or Python packages communicate with the .NET side through simple client / server interactions. Your .NET libraries are loaded by a runner
CLRServer.exe
that provides a TCP-based API, giving full visibility into your library(ies).On first use from R or Python, the package will start the .NET bridge server (or alternatively connect to an existing server). If the server is started from within VisualStudio, Xamarin Studio, or other tool, can be run in debug mode, so that you can debug your libraries as they are called from R or Python.
When a method is first called the code looks for all methods in a class that may match based on name and number of arguments and then picks the method from that subset with the closest convertible signature. The argument set need not be a perfect match in terms of types provided that the types can be reasonably converted. For example strings will be converted to enum values if a given signature requires an enum, integers can be converted to floating point, double[] arrays can be applied to double[] or Vector, etc. These signatures are cached so that subsequent calls avoid scanning.
For example if a class has 2 overloaded public methods "F":
public double F (double x, Vector<double> series)
public double F (Direction dir, Vector<double> series)
where Direction is
enum Direction { Up, Down }
. If the object is called from R or python as:the second method would be chosen given that 'Up' is convertible to
Direction.Up
and the numeric array is convertible toVector<double>
.Initialization
The .NET bridge server (CLRServer.exe) will not have access to your code unless you indicate a DLL to be loaded. One needs to instruct the server to load a dll or dlls from your environment. There are a number of ways to do this:
From within R one has two options. The first approach is to set an environment variable either within the R session or externally:
The second approch is to explicitly call the rDotNet initialization function:
In python, the CLR is initialized using the
CLRApi
constructor. .NET object can then be created and interacted with directly:Example
Assuming the following (contrived) .NET classes:
The R api uses the $ syntax to reference members much like other R object approaches. Here is how we could call the above from R:
The python API provides .NET objects as first class citizens in Python as proxy objects. One can interact with these proxy objects with normal python syntax. Here is how we could call the above from python:
Repository Locations
The R and Python packages were uploaded and approved by CRAN and PyPi respectively. The packages reside at:
Installation
Please refer to the Installation document.