是否可以调用R统计函数来优化C#函数

时间:2013-06-20 13:19:12

标签: c# r dll

我想知道是否可以从C#调用r统计优化函数(这里我想使用regnoud),而要优化的函数是用C#编写的。 我找到了RDotNet库,但有了它我无法评估来自R的C#函数。 换句话说,问题在于R在优化时需要评估函数,但由于函数在C#代码中,因此无法执行。

是否有使用.dll或其他库的解决方案?
感谢。

3 个答案:

答案 0 :(得分:9)

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

首先,您需要创建一个包含您的函数的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”
  3. 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。我们差不多了!不要放弃:)现在,您有一个C#DLL公开为COM对象和一个可以调用此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。祝你好运!

答案 1 :(得分:1)

如果我清楚地理解你的需要,你就会遇到一个C#调用R回拨C#的优化问题。

我认为有一种方法可以在R.NET当前设置一个回调函数(“函数指针”,“委托”,因为它们可以根据你的联系方式调用)。我很可能有非常相似的需求,如果我可以分配时间,可能会在未来为R.NET做出贡献。

同时,如果你可以使用R调用C#工作,即R是你的应用程序的入口点,那么使用rClr这绝对是可行的。 包。我让同事们对用C#编写的模型进行优化和MCMC分析。一个tutorial是使用C#从R优化的非常简化但实际的情况。

答案 2 :(得分:0)

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

查看类似的内容。现在我对C#了解不多,所以如果我说任何不可能的事情,请不要伤害我:

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