部署从 MATLAB Handle 类继承的 MATLAB 类
支持的 .NET 版本:.NET 6.0 或更高版本
数据 API:MATLAB® Data Array for .NET
此示例说明如何打包从 MATLAB 句柄类继承的 MATLAB 类并将其部署到 C# 应用程序。它使用 .NET 的 MATLAB Data API 来管理 MATLAB 代码和 C# 应用程序之间的数据交换。该工作流支持 Windows®、Linux® 和 macOS。
自 R2023b 起,带有包含 MATLABMATLAB 的 .NET 应用程序可以跨 Windows、Linux 和 macOS 平台开发和发布。这意味着可以在这三种平台中的任一平台上进行开发,然后发布到另外两个平台上。但是,自 R2024a 起才支持部署从 MATLAB 句柄类继承的 MATLAB 类。
请注意,虽然开发和发布可以在任何平台上进行,但仍可能存在特定于平台的细微差别和问题。某些库或函数在不同平台上的行为可能会有所不同,开发人员应在目标平台上彻底测试他们的应用程序以确保预期的行为。
前提条件
创建一个对 MATLAB 搜索路径可见的新工作文件夹。此示例使用名为
work的文件夹。验证您是否已设置 .NET 开发环境。有关详细信息,请参阅设置 .NET 开发环境。
验证您是否已满足所有 MATLAB .NET 目标要求。有关详细信息,请参阅MATLAB Compiler SDK .NET 目标要求。
最终用户必须安装 MATLAB Runtime 才能运行应用程序。有关详细信息,请参阅下载并安装 MATLAB Runtime。
出于测试目的,您可以使用安装的 MATLAB 来代替 MATLAB Runtime。
验证您是否已安装 .NET 6.0 SDK 或更高版本或 Microsoft® Visual Studio® 2022(v17.0 或更高版本)。您可以在系统命令提示符下输入
dotnet --info来验证 .NET 6.0 是否已安装。您可以从 https://dotnet.microsoft.com/download 下载特定于您的操作系统的 .NET SDK 版本。
数据管理
要在部署的 MATLAB 代码和 .NET 应用程序之间交换数据,请使用适用于 .NET 的 MATLAB Data API。MATLAB 引擎也使用此 API。有关概述,请参阅从 .NET 调用 MATLAB。有关详细信息,请参阅:
句柄类支持
从继承自 MATLAB 句柄类的 MATLAB 类生成 .NET 程序集时,现在支持以下功能:
复制行为:生成的 .NET 程序集复制了 MATLAB 句柄类复制行为。在 MATLAB 中,句柄对象是引用类型,这意味着当您复制这些对象时,原始变量和新变量都引用同一个对象。当您部署到 .NET 时,此行为现在保留在 C# 翻译中。
关系运算符:.NET 程序集中基于 MATLAB 句柄类定义创建的 C# 对象支持关系运算。这允许在 C# 中使用标准关系运算符(
==、!=、<、>、<=、>=),类似于它们在 MATLAB 中的功能。isvalid方法支持:.NET 程序集包括对isvalid方法的支持,与 MATLAB 句柄类行为一致。在 C# 中,此方法检查从 MATLAB 句柄类创建的对象是否仍然有效或已被删除,从而反映 MATLAB 中的功能。delete方法支持:对于从 MATLAB 句柄类派生的 C# 对象,.NET 程序集也支持delete方法。此函数可以以与 MATLAB 中处理删除的方式一致的方式删除这些对象。
创建从 MATLAB Handle 类继承的 MATLAB 类
使用以下代码创建一个名为 BankAccount.m 的 MATLAB 文件:
classdef BankAccount < handle % BankAccount - A class for managing a bank account. % % This class provides methods to deposit, withdraw, and check the % balance of a bank account. % % BankAccount Properties: % Balance - The current balance of the account (private access). % % BankAccount Methods: % BankAccount - Constructor, initializes account with a balance. % deposit - Deposit money into the account. % withdraw - Withdraw money from the account. % checkBalance - Check the current balance of the account properties (Access = private) Balance (1,1) double {mustBeReal} end methods % Constructor to initialize the account with a balance function obj = BankAccount(initialBalance) arguments (Input) initialBalance (1,1) double {mustBeReal} end if nargin == 0 initialBalance = 0; end obj.Balance = initialBalance; end % Method to deposit money function deposit(obj, amount) arguments (Input) obj (1,1) BankAccount amount (1,1) double {mustBeReal} end if amount > 0 obj.Balance = obj.Balance + amount; else error('Amount must be positive'); end end % Method to withdraw money function withdraw(obj, amount) arguments (Input) obj (1,1) BankAccount amount (1,1) double {mustBeReal} end if amount <= obj.Balance && amount > 0 obj.Balance = obj.Balance - amount; else error('Insufficient funds or invalid amount'); end end % Method to check the balance function bal = checkBalance(obj) arguments (Input) obj (1,1) BankAccount end arguments (Output) bal (1,1) double {mustBeReal} end bal = obj.Balance; end end end
资深 MATLAB 用户可能会发现,在类中看到 properties 模块,在方法或函数中看到 arguments 模块,并且每个块都详细记录数据类型信息,这是很不寻常的。这两个模块都允许您使用等效的 MATLAB 类型表示 C# 数据类型。例如,如果您的 C# 应用程序采用 double 数据类型来表示一个值,那么您现在可以在 MATLAB 中将其表示为 double。您还可以将 MATLAB 对象指定为参量或属性类型。例如,checkBalance 方法指定 BankAccount 作为输入参量的类型,并指定 double 作为输出参量的类型。
在命令提示符下测试 MATLAB 类。
%% Create a new bank account with an initial balance of 100 account = BankAccount(100); %% Deposit 50 into the account account.deposit(50); disp(['Balance after deposit: ', num2str(account.checkBalance())]); %% Withdraw 30 from the account account.withdraw(30); disp(['Balance after withdrawal: ', num2str(account.checkBalance())]); %% Create a joint account that references the same existing account jointAccount = account; %% Deposit 20 using the shared reference jointAccount.deposit(20); disp(['Balance from sharedAccount: ', num2str(jointAccount.checkBalance())]); disp(['Balance from original account: ', num2str(account.checkBalance())]);
Balance after deposit: 150 Balance after withdrawal: 120 Balance from sharedAccount: 140 Balance from original account: 140
使用 compiler.build.dotNETAssembly 创建 .NET 程序集
使用 compiler.build.dotNETAssembly 函数从 MATLAB 函数创建代码存档(.ctf 文件)。
buildResults = compiler.build.dotNETAssembly("BankAccount.m", ... Interface="matlab-data",... Verbose="on", ... OutputDir=".\output", ... AssemblyName="Example.Banking")
尽管通过 AssemblyName 属性提供程序集名称不是强制性的,但强烈建议这样做。这样做会为生成的 .NET 程序集和 C# 文件提供更清晰的命名空间。如果没有它,名为 example 的根命名空间会自动追加到子命名空间,从而导致命名空间结构混乱且可能令人困惑。
该类生成一套文件(如下所列),并将它们放在指定的 output 目录中。其中,集成过程中使用的关键文件是包含 MATLAB 代码的代码存档(.ctf 文件)、C# (.cs) 代码文件和 .NET 程序集(.dll 文件)。有关其他文件的信息,请参阅打包 MATLAB 函数后生成的文件。
P:\MATLAB\WORK\OUTPUT
│ Banking.csproj
│ Banking.ctf
│ Banking.deps.json
│ Banking.dll
│ GettingStarted.html
│ includedSupportPackages.txt
│ mccExcludedFiles.log
│ readme.txt
│ requiredMCRProducts.txt
│ unresolvedSymbols.txt
│
└───strongly_typed_interface
BankAccount.cs要完成集成,您可以选择以下两个选项之一:
将
Banking.ctf代码存档文件与BankAccount.csC# 代码文件结合使用。将
Banking.ctf代码存档文件与Banking.dll.NET 程序集文件结合使用。
经检查,您会注意到该函数还生成一个 Banking.csproj 工程文件。该文件是专门为创建相应的 Banking.dll .NET 程序集文件而生成的。但是,它不应被误认为是 .NET 工程的模板,并且不得在该环境中使用。
此示例采用第一个集成选项来说明类型映射机制。在工作流的相关阶段插入了使用第二种选项的相关指导。
您可以检查以下 C# 代码文件的内容:
MATLAB 类与生成的 C# 类之间的映射
| MATLAB 类元素 | C# 类元素a |
|---|---|
BankAccount 类定义 | [MATLABClass("BankAccount")] |
BankAccount 构造函数 | public BankAccount(MATLABProvider _matlab, double initialBalance) |
deposit 方法 | public void deposit(double amount) |
withdraw 方法 | public void withdraw(double amount) |
checkBalance 方法 |
|
从 MATLAB 句柄类继承的关系运算符
|
|
从 MATLAB 句柄类继承的 delete 方法 | public void delete() |
从 MATLAB 句柄类继承的 isvalid 方法 | public void isvalid(), public void isvalid(out dynamic validity) |
a Input arguments are in C# data types corresponding to those defined in the MATLAB class' arguments block. | |
将 MATLAB 代码集成到 .NET 应用程序中
您可以在首选的 C# 开发环境中完成集成过程,包括文本编辑器以及 .NET SDK 命令行 API,或者 Windows 和 Microsoft macOS 上的 Visual Studio 等替代方案。此示例向您说明如何使用两个选项完成集成。有关详细信息,请参阅设置 .NET 开发环境。
使用 .NET SDK 命令行 API 构建应用程序
如果您使用的是 Microsoft Visual Studio,请参阅使用 Microsoft Visual Studio 构建应用程序 (Windows)。
在 Windows 中打开命令提示符并导航到本示例中使用的
work文件夹。在命令行中输入:
dotnet new console --framework net6.0 --name BankAccountConsoleApp此命令创建一个名为
BankAccountConsoleApp的文件夹,其中包含以下内容:obj文件夹BankAccountConsoleApp.csproj工程文件Program.csC# 源文件
将由
compiler.build.dotNETAssembly函数生成的以下文件与dotnet newC# 应用程序代码文件一起复制到Program.cs创建的工程文件夹中:来自
.cs目录的...\work\output\strongly_typed_interface\C# 包装器文件。来自
Banking.ctf目录的代码存档...\work\output。
编辑工程以添加程序集依赖项和由
compiler.build.dotNETAssembly函数生成的Banking.ctf代码存档文件。在文本编辑器中打开工程文件,并使用以下程序集包含
<Reference>标记内的<ItemGroup>工程标记:MathWorks.MATLAB.Runtime.dllMathWorks.MATLAB.Types.dll
注意
如果您使用由
compiler.build.dotNETAssembly函数生成的Banking.dll.NET 程序集而不是 C# 代码文件,请将其作为引用包含在同一个<ItemGroup>标记。将
Banking.ctf代码存档文件作为内容文件包含到工程中。将
Banking.ctf代码存档文件作为内容文件添加进<ItemGroup>标记。添加标记
CopyToOutputDirectory并将其设置为Always。此步骤确保在构建过程中将Banking.ctf文件复制到输出文件夹。这意味着当您构建工程时,该文件与您构建的.exe文件位于同一目录中。添加标记
CopyToPublishDirectory并将其设置为Always。此步骤确保将Banking.ctf文件复制到此工程发布到的跨平台文件夹中。
一旦添加了程序集依赖项并将
Banking.ctf作为内容文件包含进来,您的工程文件将如下所示:
BankAccountConsoleApp.csproj(Windows)
BankAccountConsoleApp.csproj(Linux)
BankAccountConsoleApp.csproj(macOS)注意
如果您选择在 C# 代码文件上使用由
compiler.build.dotNETAssembly生成的Banking.dll.NET 程序集,请记住取消注释工程文件中对Banking.dll的引用标记。此更改可确保您的工程正确使用.dll文件。将
Program.csC# 文件中的代码替换为以下代码:注意
在 macOS 系统上开发和操作时,将代码从
Main方法转换到名为MainFunc的新函数。随后,从MATLABRuntime.SetupMacRunLoopAndRun方法中调用Main,并将MainFunc与命令行参量一起作为参数传递。MATLABRuntime.SetupMacRunLoopAndRun 对于 macOS 环境来说是不可或缺MATLABRuntime.SetupMacRunLoopAndRun,因为它允许 MATLAB 与 Core Foundation Run Loop (CFRunLoop) 交互,这是一种特定于 macOS 的机制,用于处理用户输入或计时器事件等事件。有关详细信息,请参阅MathWorks.MATLAB.Runtime.MATLABRuntime。在命令行中,输入以下命令来构建您的工程:
dotnet build BankAccountConsoleApp.csproj
运行 C# 应用程序
为了测试目的,您可以从 MATLAB 命令提示符运行该应用程序。这不需要安装 MATLAB Runtime。
在 MATLAB 命令提示符下,导航到包含可执行文件的目录,然后输入以下内容运行您的应用程序:
!dotnet run应用程序显示平均值。
Balance after deposit: 150 Balance after withdrawal: 120 Balance from joint account: 140 Balance original account: 140
注意
当您准备部署此应用程序时,请确保目标系统已安装 MATLAB Runtime。有关详细信息,请参阅下载并安装 MATLAB Runtime。在 Linux 和 macOS 系统上,必须在运行应用程序之前分别设置 LD_LIBRARY_PATH 和 DYLD_LIBRARY_PATH 运行时路径。有关详细信息,请参阅针对部署设置 MATLAB Runtime 路径。
使用 Microsoft Visual Studio 构建应用程序 (Windows)
打开 Microsoft Visual Studio 并创建一个名为
BankAccountConsoleApp的 C# Console App。选择
.NET 6.0 (Long-term support)作为框架。将
Program.cs文件中默认生成的源代码替换为此示例页面中的Program.cs文件中提供的特定源代码。选择以下两个选项之一:
要合并由
compiler.build.dotNETAssembly函数生成的BankAccount.csC# 代码文件,请导航到 Solution Explorer,右键点击您的工程,然后选择 Add > Existing Item。使用对话框查找并添加BankAccount.csC# 代码文件。如果您更喜欢使用由
compiler.build.dotNETAssembly函数生成的Banking.dll.NET 程序集,请在 Solution Explorer 中右键点击您的解决方案,然后选择 Edit Project File。在这里,您需要在现有文件中添加对Banking.dll文件的引用<ItemGroup>标记。
查看上面列出的工程文件之一作为参考。
添加以下程序集依赖项:
MathWorks.MATLAB.Runtime.dllMathWorks.MATLAB.Types.dll
将
Banking.ctf代码存档文件作为内容文件添加到工程中。在 Solution Explorer 中右键点击您的工程,然后选择 Add > Existing Item。在对话框中,浏览文件并添加文件。在 Solution Explorer 中右键点击
Banking.ctf文件并选择 Properties。在 Properties 窗口中,将 Build Action 设置为 Content,并将 Copy to Output Directory 设置为 Copy always。在 Solution Explorer 中右键点击您的工程并选择 Edit Project File。
BankAccountConsoleApp.csproj工程文件在编辑器中打开。添加<CopyToPublishDirectory>标记正下方<CopyToOutputDirectory>标记并将其设置为Always。BankAccountConsoleApp.csproj工程文件的已编辑部分如下所示:... <ItemGroup> <Content Include="Banking.ctf"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToPublishDirectory>Always</CopyToPublishDirectory> </Content> </ItemGroup> ...在菜单栏上,选择 Build,然后选择 Build Solution 以在 Visual Studio 中构建应用程序。
编译过程会生成一个名为
BankAccountConsoleApp.exe的可执行文件。按 Ctrl+F5 从 Visual Studio 运行应用程序。或者,您可以从系统终端执行生成的可执行文件:
> cd C:\work\BankAccountConsoleApp\BankAccountConsoleApp\bin\Debug\net6.0 > BankAccountConsoleApp.exe
应用程序会返回与 MATLAB 示例代码相同的输出。
Balance after deposit: 150 Balance after withdrawal: 120 Balance from joint account: 140 Balance original account: 140
提示
如果您无法构建应用程序,请将解决方案平台从
Any CPU更改为x64。如果您无法从 Visual Studio 运行应用程序,请打开 Developer Command Prompt for Visual Studio,然后输入
devenv /useenv启动 Visual Studio。然后,打开您的工程并运行您的应用程序。
另请参阅
compiler.build.dotNETAssembly | compiler.build.DotNETAssemblyOptions | MathWorks.MATLAB.Types.RunOptions