6

我想知道是否可以从 C# 调用 r 统计优化函数(这里我想使用 regnoud),而要优化的函数是用 C# 编写的。我找到了 RDotNet 库,但我无法从 R 评估 C# 函数。换句话说,问题是 R 在优化时需要评估函数但他不能这样做,因为函数在 C# 代码中。

有没有像使用 .dll 或其他库这样的解决方案?
谢谢。

4

3 回答 3

12

在使用有点复杂的方法之前,我已经这样做了,但它确实有效!

首先,您需要创建一个包含您的函数的 C# DLL。您可以在 Visual Studio 中通过在创建新项目时选择“类库”作为选项来执行此操作。.cs 文件中的代码应如下所示

namespace MyNamespace
{
    //expose an interface with functions to be called from R
    public interface MyInterface
    {
       string MyFunction(string name);
    }

    //create a class that implements the above interface
    public class MyClass : MyInterface
    {
      public string MyFunction(string name)
      {
         return "Hello " + name;
      }
    }

}

现在编译您的项目,您将获得一个 C# DLL。此 DLL 是托管 DLL,它不同于本机 C/C++ DLL。它不能直接从非 .Net 语言中使用,因此需要作为 COM 对象公开。您可以通过以下两种方式之一执行此操作

  1. 在 Visual Studio 中,您可以转到项目属性,单击“应用程序”选项卡下的“程序集信息”按钮,然后选中“使程序集 COM 可见”复选框。
  2. 或者,您可以使用 .net 安装文件夹中的 regasm.exe 将 DLL 注册为 COM 组件。这是描述此过程的链接。http://msdn.microsoft.com/en-us/library/tzat5yw6(v=vs.71).aspx。该命令通常是“regasm myTest.dll /tlb:myTest.tlb”

COM 注册过程现在将在与您的 DLL 相同的文件夹中创建一个 .tlb 文件。保留此 .tlb 文件。我们将在下一步中需要它

下一步是创建一个可以调用 COM DLL 的 C++ DLL。这一步是必要的,因为 R 可以直接调用 C++ DLL,但不能直接调用 COM(如果我错了请纠正我,如果您知道从 R 调用 COM 的更好方法,请跳过这一步)。dllmain.cpp 中的 C++ DLL 代码如下所示(确保滚动查看完整代码)

#include "stdafx.h"
#include <iostream>

//import the .tlb file create by COM registration

#import "path_to_Dll\MyDll.tlb" named_guids raw_interfaces_only

    void _cdecl MyCPPFunction(char ** strName)
    {
        //Initialize COM
        HRESULT hr = CoInitialize(NULL);

        //create COM interface pointer
        MyNamespace::MyInterfacePtr myPtr;

        //create instance of COM class using the interface pointer
        HRESULT hr2 = myPtr.CreateInstance(MyNamespace::CLSID_MyClass);

       //create variable to hold output from COM.
       BSTR output;

       //call the COM function
       myPtr->MyFunction(_bstr_t(strName[0]), &output);

       //convert the returned BSTR from .net into char*
       int length = (int) SysStringLen(output);
       char *tempBuffer;
       tempBuffer = (char *) malloc(1 + length);
       WideCharToMultibyte(CP_ACP, 0, output, -1, tempBuffer, length, NULL, NULL);
       tempBuffer[length] = '\0';

       //release interface
       myPtr->Release();

       //uninitialize COM
       if(hr == S_OK)
         CoUninitialize();

       //set output in input for returning to R (this is weird but the only way I could make it work)
       strName[0] = tempBuffer;
    }

现在编译您的项目,您将获得一个 C++ DLL。我们现在快到了!不要放弃:)。现在,您有一个作为 COM 对象公开的 C# DLL 和一个可以调用此 COM 对象的 C++ DLL。最后一步是从 R 调用 C++ 函数。这是执行此操作的 R 代码

#load C++ DLL
dyn.load("path_to_C++_DLL")

#call function in C++ DLL and pass in a test name.
# The C++ DLL will in turn call the C# function
output <- .C("MyCPPFunction", as.character("Peter"))

#print output
print(output)

您应该会在 R 控制台中看到 C# 中显示的“Hello Peter”!需要注意的非常重要的一点。

始终使用“任何 CPU”选项编译 COM DLL。始终编​​译 C++ DLL 以匹配您的 R 安装!例如,如果您安装了 32 位 R,请确保将 C++ DLL 编译为 32 位 DLL。如果您安装了 64 位 R 并想使用它,请确保将 C++ DLL 编译为 64 位 DLL。祝你好运!

于 2013-07-10T16:19:32.743 回答
1

如果我清楚地了解您的需求,那么您有一个 C# 调用 R 回调 C# 的优化问题。

我认为目前没有办法在R.NET中设置回调函数(“函数指针”、“委托”,因为它们可以根据您与谁交谈来调用)。如果我能分配时间,我可能有非常相似的需求,并且将来可能会为 R.NET 做出贡献。

同时,如果您可以接受从 R 调用 C# 的工作,即 R 是您的应用程序的入口点,那么使用rClr 包绝对是可行的。我有同事对用 C# 编写的模型进行优化和 MCMC 分析。一个教程是使用 C# 从 R 优化的一个非常简化但现实的案例。

于 2013-09-06T02:22:29.317 回答
0

http://www.codeproject.com/Articles/25819/The-R-Statistical-Language-and-C-NET-Foundations

看看这样的东西。现在我对 C# 了解不多,所以如果我说任何不可能的话,请不要伤害我:

尝试将要优化的函数保存为 C# 中的字符,然后使用此 StatConnector 库将其发送到 R(我对它的经验有限。)假设您将方程保存为 R 中的“z”,然后您可以使用“get(z)”作为变量之一调用您的 R 脚本。

于 2013-07-08T16:54:22.830 回答