主要内容

本页采用了机器翻译。点击此处可查看最新英文版本。

将接受结构体数组作为输入参量的 MATLAB 函数部署到 .NET 应用程序

支持的 .NET 版本:.NET 6.0 或更高版本

数据 API:MATLAB® Data Array for .NET

此示例说明如何打包接受结构体数组作为输入的 MATLAB 函数并将其与用 C# 编写的 .NET 应用程序一起部署。Windows®、Linux®macOS 系统支持此工作流。本示例使用基于 Windows 工作流。

自 R2023a 起,可以跨 Windows、Linux 和 macOS 平台开发和发布包含打包的 MATLAB 代码的 .NET 应用程序。这意味着可以在这三种平台中的任一平台上进行开发,然后发布到另外两个平台上。在此版本之前,.NET 应用程序只能从 Windows 发布到 Linux 和 macOS

请注意,虽然开发和发布可以在任何平台上进行,但仍可能存在特定于平台的细微差别和问题。某些库或函数在不同平台上的行为可能会有所不同,开发人员应在目标平台上彻底测试他们的应用程序以确保预期的行为。

前提条件

  • 创建一个对 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 函数

使用以下代码创建一个名为 analyzeData.m 的 MATLAB 文件:

function outputStruct = analyzeData(inputStruct)
% This function takes a MATLAB struct 'inputStruct' as input, performs
% statistical analysis on each numeric field, and returns a struct
% 'outputStruct' containing the results of these analyses. Non-numeric
% fields in the input struct are ignored.
%
% Inputs:
%   inputStruct - Struct with fields containing numeric data.
%
% Outputs:
%   outputStruct - Struct with the same fields as 'inputStruct'. Each
%                  field is a struct with 'mean', 'std', and 'max'
%                  of the corresponding field in 'inputStruct'.
%
% Use arguments block to map a MATLAB type to a C# type
% Struct arrays in MATLAB map to a MATLAB Data Array 
% MATLABStruct type in C#
arguments (Input)
    inputStruct (1,1) struct
end

arguments (Output)
    outputStruct (1,1) struct
end

% Initialize outputStruct
outputStruct = struct();

% Get field names from the input struct
fields = fieldnames(inputStruct);

% Loop over each field and perform analysis
for i = 1:length(fields)
    fieldName = fields{i};

    % Ensure the field contains numeric data
    if isnumeric(inputStruct.(fieldName))
        % Calculate mean
        outputStruct.(fieldName).mean = mean(inputStruct.(fieldName));

        % Calculate standard deviation
        outputStruct.(fieldName).std = std(inputStruct.(fieldName));

        % Calculate max value
        outputStruct.(fieldName).max = max(inputStruct.(fieldName));
    else
        warning('Field %s is not numeric and was skipped.', fieldName);
    end
end
end

资深 MATLAB 用户可能会发现 arguments 模块的存在不太寻常。arguments 模块允许您用等效的 MATLAB 类型表示 C# 数据类型。

在命令提示符下测试 MATLAB 函数。

data = struct();
data.temperatures = [72, 75, 69, 68, 70];
data.pressures = [30, 29.5, 30.2, 29.9, 30.1];
output = analyzeData(data)
output.temperatures(:)
output.pressures(:)
output = 
  struct with fields:

    temperatures: [1×1 struct]
       pressures: [1×1 struct]
ans = 
  struct with fields:

    mean: 70.8000
     std: 2.7749
     max: 75
ans = 
  struct with fields:

    mean: 29.9400

使用 compiler.build.dotNETAssembly 创建 .NET 程序集

使用 compiler.build.dotNETAssembly 函数从 MATLAB 函数创建代码存档(.ctf 文件)。

buildResults = compiler.build.dotNETAssembly("analyzeData.m", Interface="matlab-data",...
    Verbose="on", OutputDir=".\output", AssemblyName="AnalyzeData")

尽管通过 AssemblyName 属性提供程序集名称不是强制性的,但强烈建议这样做。这样做会为生成的 .NET 程序集和 C# 文件提供更清晰的命名空间。如果没有它,名为 example 的根命名空间会自动追加到子命名空间,从而导致命名空间结构混乱且可能令人困惑。

该函数生成一套文件(如下所列),并将它们放在指定的 output 目录中。其中,集成过程中使用的关键文件是包含 MATLAB 代码的代码存档(.ctf 文件)、C# (.cs) 代码文件和 .NET 程序集(.dll 文件)。有关其他文件的信息,请参阅打包 MATLAB 函数后生成的文件

P:\MATLAB\WORK\OUTPUT
│   AnalyzeData.csproj
│   AnalyzeData.ctf
│   AnalyzeData.deps.json
│   AnalyzeData.dll
│   GettingStarted.html
│   includedSupportPackages.txt
│   mccExcludedFiles.log
│   readme.txt
│   requiredMCRProducts.txt
│   unresolvedSymbols.txt
│
└───strongly_typed_interface
        analyzeData.cs

要完成集成,您可以选择以下两个选项之一:

  • AnalyzeData.ctf 代码存档文件与 analyzeData.cs C# 代码文件结合使用。

  • AnalyzeData.ctf 代码存档文件与 AnalyzeData.dll .NET 程序集文件结合使用。

经检查,您会注意到该函数还生成一个 AnalyzeData.csproj 工程文件。该文件是专门为创建相应的 AnalyzeData.dll .NET 程序集文件而生成的。但是,它不应被误认为是 .NET 工程的模板,并且不得在该环境中使用。

此示例采用第一个集成选项来说明类型映射机制。在工作流的相关阶段插入了使用第二种选项的相关指导。

您可以检查以下 C# 代码文件的内容:

 analyzeData.cs

analyzeData.cs C# 代码文件中,MATLAB 函数的 struct 参量规范映射到基于 MATLAB 数据数组的 C# 等效项 MATLABStruct

    arguments (Input)
        inputStruct (1,1) struct
    end
   
MATLABStruct inputStruct 
    arguments (Output)
        outputStruct (1,1) struct
    end
    public static void analyzeData(MATLABProvider _matlab, 
                  MATLABStruct inputStruct,  out MATLABStruct outputStruct){
        dynamic _dynMatlab = _matlab;
        outputStruct = 
              (MATLABStruct)_dynMatlab.analyzeData(new RunOptions(nargout:1),inputStruct);
    }

MATLAB 代码集成到 .NET 应用程序中

您可以在首选的 C# 开发环境中完成集成过程,包括文本编辑器以及 .NET SDK 命令行 API,或者 Windows 和 Microsoft macOS 上的 Visual Studio 等替代方案。此示例向您说明如何使用两个选项完成集成。有关详细信息,请参阅设置 .NET 开发环境

使用 .NET SDK 命令行 API 构建应用程序

如果您使用的是 Microsoft Visual Studio,请参阅使用 Microsoft Visual Studio 构建应用程序 (Windows)

  1. 在 Windows 中打开命令提示符并导航到本示例中使用的 work 文件夹。

  2. 在命令行中输入:

    dotnet new console --framework net6.0 --name StructConsoleApp

    此命令创建一个名为 StructConsoleApp 的文件夹,其中包含以下内容:

    • obj 文件夹

    • StructConsoleApp.csproj 工程文件

    • Program.cs C# 源文件

  3. 将由 compiler.build.dotNETAssembly 函数生成的以下文件与 dotnet new C# 应用程序代码文件一起复制到 Program.cs 创建的工程文件夹中:

    • 来自 .cs 目录的 ...\work\output\strongly_typed_interface\ C# 包装器文件。

    • 来自 ...\work\output 目录的代码存档 AnalyzeData.ctf

  4. 编辑工程以添加程序集依赖项和由 compiler.build.dotNETAssembly 函数生成的 AnalyzeData.ctf 代码存档文件。

    1. 在文本编辑器中打开工程文件,并使用以下程序集包含 <Reference> 标记内的 <ItemGroup> 工程标记:

      • MathWorks.MATLAB.Runtime.dll

      • MathWorks.MATLAB.Types.dll

       Windows 路径

       LinuxmacOS 路径

      注意

      如果您使用由 compiler.build.dotNETAssembly 函数生成的 AnalyzeData.dll .NET 程序集而不是 C# 代码文件,请将其作为引用包含在同一个 <ItemGroup> 标记。

    2. AnalyzeData.ctf 代码存档文件作为内容文件包含到工程中。

      • AnalyzeData.ctf 代码存档文件作为内容文件添加进 <ItemGroup> 标记。

      • 添加标记 CopyToOutputDirectory 并将其设置为 Always。此步骤确保在构建过程中将 AnalyzeData.ctf 文件复制到输出文件夹。这意味着当您构建工程时,该文件与您构建的 .exe 文件位于同一目录中。

      • 添加标记 CopyToPublishDirectory 并将其设置为 Always。此步骤确保将 AnalyzeData.ctf 文件复制到此工程发布到的跨平台文件夹中。

    一旦添加了程序集依赖项并将 AnalyzeData.ctf 作为内容文件包含进来,您的工程文件将如下所示:

     StructConsoleApp.csproj (Windows)

     StructConsoleApp.csproj (Linux)

     StructConsoleApp.csproj (macOS)

    注意

    如果您选择在 C# 代码文件上使用由 compiler.build.dotNETAssembly 生成的 AnalyzeData.dll .NET 程序集,请记住取消注释工程文件中对 AnalyzeData.dll 的引用标记。此更改可确保您的工程正确使用 .dll 文件。

  5. Program.cs C# 文件中的代码替换为以下代码:

     Program.cs

    注意

    macOS 系统上开发和操作时,将代码从 Main 方法转换到名为 MainFunc 的新函数。随后,从 MATLABRuntime.SetupMacRunLoopAndRun 方法中调用 Main,并将 MainFunc 与命令行参量一起作为参数传递。MATLABRuntime.SetupMacRunLoopAndRun 对于 macOS 环境来说是不可或缺 MATLABRuntime.SetupMacRunLoopAndRun,因为它允许 MATLAB 与 Core Foundation Run Loop (CFRunLoop) 交互,这是一种特定于 macOS 的机制,用于处理用户输入或计时器事件等事件。有关详细信息,请参阅 MathWorks.MATLAB.Runtime.MATLABRuntime

  6. 在命令行中,输入以下命令来构建您的工程:

    dotnet build StructConsoleApp.csproj

运行 C# 应用程序

为了测试目的,您可以从 MATLAB 命令提示符运行该应用程序。这不需要安装 MATLAB Runtime

在 MATLAB 命令提示符下,导航到包含可执行文件的目录,然后输入以下内容运行您的应用程序:

!dotnet run

应用程序显示平均值。

Field: temperatures
  mean: 70.8000
  std: 2.7749
  max: 75.0000
Field: pressures
  mean: 29.9400
  std: 0.2702
  max: 30.2000

注意

当您准备部署此应用程序时,请确保目标系统已安装 MATLAB Runtime。有关详细信息,请参阅下载并安装 MATLAB Runtime。在 Linux 和 macOS 系统上,必须在运行应用程序之前分别设置 LD_LIBRARY_PATHDYLD_LIBRARY_PATH 运行时路径。有关详细信息,请参阅针对部署设置 MATLAB Runtime 路径

使用 Microsoft Visual Studio 构建应用程序 (Windows)

  1. 打开 Microsoft Visual Studio 并创建一个名为 StructConsoleApp 的 C# Console App

  2. 选择 .NET 6.0 (Long-term support) 作为框架。

  3. Program.cs 文件中默认生成的源代码替换为此示例页面中的 Program.cs 文件中提供的特定源代码。

  4. 选择以下两个选项之一:

    • 要合并由 compiler.build.dotNETAssembly 函数生成的 analyzeData.cs C# 代码文件,请导航到 Solution Explorer,右键点击您的工程,然后选择 Add > Existing Item。使用对话框查找并添加 analyzeData.cs C# 代码文件。

    • 如果您更喜欢使用由 compiler.build.dotNETAssembly 函数生成的 AnalyzeData.dll .NET 程序集,请在 Solution Explorer 中右键点击您的解决方案,然后选择 Edit Project File。在这里,您需要在现有文件中添加对 AnalyzeData.dll 文件的引用 <ItemGroup> 标记。

    查看上面列出的工程文件之一作为参考。

  5. 添加以下程序集依赖项:

    • MathWorks.MATLAB.Runtime.dll

    • MathWorks.MATLAB.Types.dll

     程序集依赖项的位置

  6. AnalyzeData.ctf 代码存档文件作为内容文件添加到工程中。在 Solution Explorer 中右键点击您的工程,然后选择 Add > Existing Item。在对话框中,浏览文件并添加文件。

  7. Solution Explorer 中右键点击 AnalyzeData.ctf 文件并选择 Properties。在 Properties 窗口中,将 Build Action 设置为 Content,并将 Copy to Output Directory 设置为 Copy always

  8. Solution Explorer 中右键点击您的工程并选择 Edit Project FileStructConsoleApp.csproj 工程文件在编辑器中打开。添加 <CopyToPublishDirectory> 标记正下方 <CopyToOutputDirectory> 标记并将其设置为 AlwaysStructConsoleApp.csproj 工程文件的已编辑部分如下所示:

    ...
    <ItemGroup>
        <Content Include="AnalyzeData.ctf">
          <CopyToOutputDirectory>Always</CopyToOutputDirectory>
          <CopyToPublishDirectory>Always</CopyToPublishDirectory>
        </Content>
    </ItemGroup>
    ...

  9. 在菜单栏上,选择 Build,然后选择 Build Solution 以在 Visual Studio 中构建应用程序。

    编译过程会生成一个名为 StructConsoleApp.exe 的可执行文件。

  10. Ctrl+F5 从 Visual Studio 运行应用程序。或者,您可以从系统终端执行生成的可执行文件:

    > cd C:\work\StructConsoleApp\StructConsoleApp\bin\Debug\net6.0
    > StructConsoleApp.exe

    应用程序会返回与 MATLAB 示例代码相同的输出。

    Field: temperatures
      mean: 70.8000
      std: 2.7749
      max: 75.0000
    Field: pressures
      mean: 29.9400
      std: 0.2702
      max: 30.2000

    提示

    • 如果您无法构建应用程序,请将解决方案平台从 Any CPU 更改为 x64

    • 如果您无法从 Visual Studio 运行应用程序,请打开 Developer Command Prompt for Visual Studio,然后输入 devenv /useenv 启动 Visual Studio。然后,打开您的工程并运行您的应用程序。

另请参阅

| |

主题

外部网站