Search code examples
c#rrclr

Give and retrieve dataset to/from rClr


I try to use rClr. I found out how to give "normal" (the basic types) parameters into a clr function. i'am also able to retrive "normal" values from the function.

The problem:
bringing many data e.g. a dataframe (with many entries per frame) into a c#-function.
Sampledataframe for a parameter

namerecord1 <- data.frame(id=1, name='A', lastname="a", coordinate=1.23456)
namerecord2 <- data.frame(id=2, name='B', lastname="b", coordinate=2.4560789)
argument <- rbind(namerecord1, namerecord2)

retrieving an array of coustumclasses from the function
Samplecode c# for the returnvalue

List<NameRecord> tmpResult = new List<NameRecord>(3);
tmpResult.Add(new NameRecord { Name = "ASDF", LastName = "asdf", Id = 1, DoubleValue = 1.456789 });
tmpResult.Add(new NameRecord { Name = "QWER", LastName = "qwer", Id = 2, DoubleValue = 2.456789 });
tmpResult.Add(new NameRecord { Name = "YXCV", LastName = "yxcv", Id = 3, DoubleValue = 3.456789 });
return tmpResult.ToArray();

What i tried

result <- clrCall(object, 'SetArgument', argument)

but in the given parameter is only an object -Array with four null values.

And at retrieving i get an object which looks really complicated. Maybe there is a way to transform it in a dataframe someway?


Solution

  • Here a solution that show to get/set complex data structures between R and c# using rClr package.

    The c# code contains:

    1. a custom class NameRecord
    2. GetObjects that returns an array of NameRecord
    3. SetObjects that gets muti parameters as array to set NamedRecord objects and returns an array of NameRecord.

    The R code:

    1. Define a handy function to transform a list of NamedRecord objects to a data.frame.
    2. Call the SetObjects and GetObjects already defined in the c# side

    R code :

    library(rClr)
    f <- file.path(path_to_net_dll,"ClassLibrary1.dll")
    clrLoadAssembly(f)
    obj <- clrNew("ClassLibrary1.Class1")
    
    ## This the most important and difficult part of the code
    rclr2R_obj <-
      function(rclr_objs){
        fields <- c("DoubleValue" ,"Id","LastName","Name" )
    
        fields_to_DF <- function(x)
          setNames(data.frame(
            lapply(fields,function(f)clrGet(x,f))),
            fields)
    
        do.call(rbind,lapply(rclr_objs,fields_to_DF))
      }
    
    new_data_frame <- rclr2R_obj(clrCall(obj,"GetObjects"))
    
    #   DoubleValue Id LastName Name
    # 1    1.456789  1     asdf ASDF
    # 2    2.456789  2     qwer QWER
    # 3    3.456789  3     yxcv YXCV
    
    names <- letters[1:4]
    lnames <- LETTERS[1:4]
    ids <- as.integer(1:4)
    vals <- as.numeric(runif(4))
    
    res <- clrCall(obj,"SetObjects",names,lnames,ids,vals)
    new_data_frame <- rclr2R_obj(res)
    
    #    DoubleValue Id LastName Name
    # 1  0.90695438  1        A    a
    # 2  0.28337886  2        B    b
    # 3  0.99027692  3        C    c
    # 4  0.05794843  4        D    d
    

    c# code

    namespace ClassLibrary1
    {
        public class Class1
        {
            // a simple c# class
            public class NameRecord
            {
                public string Name;
                public string LastName;
                public int Id;
                public double DoubleValue;
            }
    
            public NameRecord[] GetObjects()
            {
                List<NameRecord> tmpResult = new List<NameRecord>(3);
                tmpResult.Add(new NameRecord { Name = "ASDF", LastName = "asdf", Id = 1, DoubleValue = 1.456789 });
                tmpResult.Add(new NameRecord { Name = "QWER", LastName = "qwer", Id = 2, DoubleValue = 2.456789 });
                tmpResult.Add(new NameRecord { Name = "YXCV", LastName = "yxcv", Id = 3, DoubleValue = 3.456789 });
                return tmpResult.ToArray();
            }
    
    
            public NameRecord[] SetObjects(string[] names,string[] lnames,int[] ids,double[] vals)
            {
                List<NameRecord> tmpResult = new List<NameRecord>();
    
                for (var i = 0; i < names.Length; i++)
                {
                    tmpResult.Add(new NameRecord { 
                        Name = names[i], 
                        LastName = lnames[i], 
                        Id = ids[i], 
                        DoubleValue = vals[i]
                    });
                }
    
                return tmpResult.ToArray();
            }
    
    
    
        }
    }