The {rSharp} package
is a low-level interoperability bridge between R and the .NET runtime.
It offers access to .NET libraries from R, allowing to create .NET
objects, access their fields, and call their methods.
{rSharp} uses R’s native interface to C++ which then
calls the .NET runtime. To make working with .NET objects intuitive,
{rSharp} utilizes the R6 object-oriented approach. This
article will guide you through the basic usage of the package, starting
from loading an assembly to calling methods and accessing fields.
{rSharp} allows to call public and static methods
implemented in .NET assemblies and to pass data to these methods. In
return, calls will often result in some data being returned.
Where there is an obvious and natural conversion between R and .NET
data types, R values can be easily passed as is, and the return value
can be interpreted as a native R type. Most of the basic modes in R
(character,numeric,integer,
logical, and their vectors) have equivalents in .NET.
NetObject classIt is common that .NET method returns another object that can not be
directly converted to a native R type. In such cases, the method returns
an external pointer to the .NET object. The NetObject class
is used to represent such pointers in R. The NetObject
class is an R6 object that wraps the external pointer and provides
methods to interact with the .NET object with semantics familiar for the
object-oriented programming. In most cases, the user would prefer to
interact with these objects through the NetObject. If, for
any reason, the user needs to access the raw pointer, it can be done by
accessing the field $pointer of the R6 object.
NetObject instances can be passed to .NET methods as
arguments. If a method expects an array of .NET objects, all objects
within the R list must be instances of NetObject. Mixed
lists of native R types and NetObject instances are not
supported. Furthermore, the type of the array will be interpreted as
Object[].
To start working with a .NET assembly, you need to load it into the R
session. This is done using the rSharp::loadAssembly
function. In this example, we will use the library
rSharp.Examples.dll provided with this package.
library(rSharp)
assembly <- loadAssembly(system.file("extdata", "rSharp.Examples.dll", package = "rSharp"))We can get the list of all loaded assemblies using the
getLoadedAssemblies function:
Static members of a .NET class can be accessed without creating an instance of the class.
The rSharp.Examples library implements a class
SampleStaticClass with different static members. To get an
overview of the available static members of a class, you can use the
getStaticMembers function:
To explore the methods, fields, and properties of a class separately,
you can use the getStaticMethods,
getStaticFields, and getStaticProperties
functions, respectively.
To call static methods of a .NET class, you can use the
rSharp::callStatic function. If you are not sure which
arguments are expected by a certain method, you can use the
getStaticMemberSignature function to get the method’s
signature:
# Get the signature of the GetAString method
getStaticMemberSignature("rSharp.Examples.SampleStaticClass", "GetAString")
# Get the signature of the Add method
getStaticMemberSignature("rSharp.Examples.SampleStaticClass", "Add")The method GetAString returns a string and does not have
any arguments, so we can call it using the callStatic
function:
If the method has arguments, they can be passed as additional
arguments to the callStatic function, as in this case of
calling the static function Add() that requires two
integers as arguments:
Mind that we had to explicitly cast the arguments to integer, as all numeric values in R are double by default.
We can also access static fields of a class using the
getStatic and setStatic functions:
This static string is returned by the method GetAString
we called earlier. We can set the value of the static field and would
expect it to be returned by the GetAString method:
# Set the value of the static field
setStatic("rSharp.Examples.SampleStaticClass", "StaticString", "New value")
# Get the value of the static field
getStatic("rSharp.Examples.SampleStaticClass", "StaticString")
# Call the GetAString method
callStatic("rSharp.Examples.SampleStaticClass", "GetAString")So far, we were passing basic data types as arguments and receiving
basic data types as return values. However, in many cases, we would need
to work with .NET objects. For example, the method
GetInstanceObject returns an instance of the
SampleInstanceClass class. rSharp wraps such
objects in the NetObject class:
# Call the SampleInstanceClass method
instance <- callStatic("rSharp.Examples.SampleStaticClass", "GetInstanceObject")
# Check the class of the returned object
class(instance)
# Get the type of the object
instance$typeThe R6 class NetObject holds the pointer to the .NET
object and provides methods to interact with it. Thus, the constructor
of NetObject requires an external pointer to a .NET object.
The pointer can be created by calling the
newPointerFromName function. Is the constructor of the .NET
class requires arguments, they can be passed as additional arguments to
the newPointerFromName function. We can examine the
constructors of a class with the getConstructors
function:
The SampleInstanceClass has six different constructor
signature. We can create a new pointer to an instance of the class by
calling the constructor with two double arguments and create a
NetObject using the pointer:
# Create a pointer to a .NET object
pointer <- newPointerFromName("rSharp.Examples.SampleInstanceClass", as.double(1), as.double(2))
# Wrap the pointer in a new NetObject
newInstance <- NetObject$new(pointer)The more conventient way of creating a NetObject for a
new object is by calling the newObjectFromName
function:
# Create a new instance of the SampleInstanceClass
newInstance2 <- newObjectFromName("rSharp.Examples.SampleInstanceClass", as.integer(1))As with static classes, we can examine the methods, fields, and
properties of an object using the getMethods,
getFields, and getProperties methods called on
the object, respectively.
# Get the methods of the object
newInstance$getMethods()
# Get the fields of the object
newInstance$getFields()
# Get the properties of the object
newInstance$getProperties()A non-static class can also have static members, which can be listed
using the getStatic... functions:
Setting and getting non-static fields and properties of an object is
done using the set and get methods,
respectively:
# Get the value of the static field:
newInstance$get("FieldDoubleOne")
# Change the value of the static field:
newInstance$set("FieldDoubleOne", 23)
# Get the value of the static field:
newInstance$get("FieldDoubleOne")To get or set static fields, use the functions getStatic
and setStatic.
Finally, we can call the methods of the object using the
call method: