Matlab和C#混合编程文章目录 :【目录】Matlab和C#混合编程文章目录
在我的上一篇文章【原创】Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了matlab内置函数在混合编程中的优点,并通过程序找出了matlab中的大部分内置函数,当然更多人关心是如何像我所说得那样,不用直接编译,就直接在C#中调用这些内置函数。本文就带你揭开这些谜团。
声明,这篇文章是需要一点点混合编程基础的,基本概念和过程要懂一点,如果能简单成功混编一个简单的计算或者绘图例子,可以更容易理解。
1.传统的Matlab.NET混合编程步骤
传统的Matlab.NET混合编程有2种方式:
1)Matlab编写好M函数,利用deploytool编译m函数生成dll,在C#项目中引用并调用;
2)基于接口的编写方式,也是利用deploytool工具,过程繁琐一点,对编程人员素质要求高一点,但不需要进行繁琐的数据类型转换。我的博客有一篇文章专门介绍了这个混合编程方式,也有例子,大家有兴趣的可以看看:http://www.cnblogs.com/asxinyu/archive/2013/05/16/3082299.html
不管上面用哪种方式,Matlab和C#混编的基本步骤,大概都是下面的过程:
1) 编写M函数,并首先在Matlab中测试是正确可以调用的。注意命名规范,注释规范;
2) 使用命令打开 deploytool工具,设置项目名称,选择类型:.NET Assembly,然后新建一个类,并添加编写好的M函数
3) 编译,生成dll,并在C#项目中添加引用(还需要引用对应版本的MWArray),利用对象浏览器查看生成dll的方法结构,并根据Matlab和C#的类型转换规则,进行数据转换即可, 如果是接口的编程,这个过程相对要简单。
2.深入解析传统混编所生成的代码
2.1 第一步:编写M函数,并测试可以使用
为了好我们今天的目的相匹配,特意封装一个简单的内置函数,plot,来画一个简单的图形,如下所示M函数
1 function PlotTest(n) 2 %编写一个简单的函数,对plot进行简单封装一下 3 plot(1:n,1:n); 4 %测试正确,才可以进行下一步工作
注意,混编必须是m函数function的形式才能被调用。上述函数简单测试一下,没有问题(复杂的函数一定要多测试,否则后续调试非常困难)。继续下一步。
2.2 第二步:在Matlab中使用deploytool建立混编项目
在Matlab工作区输入命令:deploytool,然后得到下面界面,输入混编项目的名称,选择存储位置,关键的是类型那里一定要选择".NET Assembly"。如下图所示:
选择“OK”之后,下一步matlab界面右侧会出现项目解决方案,需要添加类名称和M文件。这个类名称,就是编译完成之后C#项目中的类对象名称,然后添加我们刚才上一步编写的“PlotTest.m”,然后编译即可,如下图所示:
到此为止,一个常规 简单的Matlab.NET混编已经完成了60%了。编译完成之后,打开“Package”选项卡,即可看到生成的dll文件,然后点击右键,打开文件夹即可,如下图所示:
2.3 查看混编生成的代码
这个过程很关键,其实包含很多信息,只不过95%以上的人都没有注意到其实混编生成的dll是有源文件的,通过查看源文件就应该知道混编的原理,只不过这是matlab自动生成 而已。那看看生成的源码吧。
打开Matlab混编项目的目录,可以看到有2个文件夹,"distrib”,“src”2个文件夹。"distrib"文件夹就是上面图中生成的dll,注意有2个dll,1个是“项目名称.dll”,一个是“项目名称Native.dll”,这2个dll的差别可以通过"distrib"文件夹源码来观察。“distrib”就是源代码的文件夹。如下图所示,src文件夹的文件示意图:
我们2.2中新建的类名是TestDemo,所以生成的的源码名称也是TestDemo,看看这2个cs文件中的代码,同时类的方法也可以在VS中通过对象浏览器来查看dll有哪些方法以及方法的参数类型。直接贴这2个cs文件的代码,顺便解释和对比下:
TestDemo.cs文件源码:
1 /* 2 * MATLAB Compiler: 4.17 (R2012a) 3 * Date: Mon Sep 09 16:19:01 2013 4 * Arguments: "-B" "macro_default" "-W" "dotnet:PlotTest,TestDemo,0.0,private" "-T" 5 * "link:lib" "-d" "D:\Work\DevelopMent_SVN\Matlab\MatlabBlog\PlotTest\src" "-w" 6 * "enable:specified_file_mismatch" "-w" "enable:repeated_file" "-w" 7 * "enable:switch_ignored" "-w" "enable:missing_lib_sentinel" "-w" "enable:demo_license" 8 * "-v" "class{TestDemo:D:\Work\DevelopMent_SVN\Matlab\MatlabBlog\PlotTest.m}" 9 */ 10 using System; 11 using System.Reflection; 12 using System.IO; 13 using MathWorks.MATLAB.NET.Arrays; 14 using MathWorks.MATLAB.NET.Utility; 15 16 #if SHARED 17 [assembly: System.Reflection.AssemblyKeyFile(@"")] 18 #endif 19 20 namespace PlotTest 21 { 22 23 /// <summary> 24 /// The TestDemo class provides a CLS compliant, MWArray interface to the M-functions 25 /// contained in the files: 26 /// <newpara></newpara> 27 /// D:\Work\DevelopMent_SVN\Matlab\MatlabBlog\PlotTest.m 28 /// <newpara></newpara> 29 /// deployprint.m 30 /// <newpara></newpara> 31 /// printdlg.m 32 /// </summary> 33 /// <remarks> 34 /// @Version 0.0 35 /// </remarks> 36 public class TestDemo : IDisposable 37 { 38 #region Constructors 39 40 /// <summary internal= "true"> 41 /// The static constructor instantiates and initializes the MATLAB Compiler Runtime 42 /// instance. 43 /// </summary> 44 static TestDemo() 45 { 46 if (MWMCR.MCRAppInitialized) 47 { 48 Assembly assembly= Assembly.GetExecutingAssembly(); 49 50 string ctfFilePath= assembly.Location; 51 52 int lastDelimiter= ctfFilePath.LastIndexOf(@"\"); 53 54 ctfFilePath= ctfFilePath.Remove(lastDelimiter, (ctfFilePath.Length - lastDelimiter)); 55 56 string ctfFileName = "PlotTest.ctf"; 57 58 Stream embeddedCtfStream = null; 59 60 String[] resourceStrings = assembly.GetManifestResourceNames(); 61 62 foreach (String name in resourceStrings) 63 { 64 if (name.Contains(ctfFileName)) 65 { 66 embeddedCtfStream = assembly.GetManifestResourceStream(name); 67 break; 68 } 69 } 70 mcr= new MWMCR("", 71 ctfFilePath, embeddedCtfStream, true); 72 } 73 else 74 { 75 throw new ApplicationException("MWArray assembly could not be initialized"); 76 } 77 } 78 79 80 /// <summary> 81 /// Constructs a new instance of the TestDemo class. 82 /// </summary> 83 public TestDemo() 84 { 85 } 86 87 88 #endregion Constructors 89 90 #region Finalize 91 92 /// <summary internal= "true"> 93 /// Class destructor called by the CLR garbage collector.