Main Content

Deploy MATLAB Class that Inherits from MATLAB Handle Class

Supported .NET Version: .NET 6.0 or higher

Data API: MATLAB® Data Array for .NET

This example shows how to package a MATLAB class that inherits from a MATLAB handle class and deploy it to a C# application. It uses the MATLAB Data API for .NET for managing data exchange between the MATLAB code and the C# application. The workflow is supported on Windows®, Linux®, and macOS.

Since R2023b, .NET applications with packaged MATLAB code containing MATLAB classes can be developed and published across Windows, Linux, and macOS platforms. This means it's possible to develop on any one of these platforms and publish to any of the other two. However, support for deploying MATLAB classes that inherit from a MATLAB handle class is only available since R2024a.

Note that while development and publishing can happen on any platform, there may still be platform-specific nuances and issues. Some libraries or functionalities might behave differently on different platforms, and developers should test their applications thoroughly on the target platform to ensure expected behavior.

Prerequisites

  • Create a new work folder that is visible to the MATLAB search path. This example uses a folder named work.

  • Verify that you have set up a .NET development environment. For details, see Setting Up .NET Development Environment.

  • Verify that you have met all of the MATLAB .NET target requirements. For details, see MATLAB Compiler SDK .NET Target Requirements.

  • End users must have an installation of MATLAB Runtime to run the application. For details, see Install and Configure MATLAB Runtime.

    For testing purposes, you can use an installation of MATLAB instead of MATLAB Runtime.

  • Verify that you have .NET 6.0 SDK or higher or Microsoft® Visual Studio® 2022 (v17.0 or higher) installed. You can verify whether .NET 6.0 is installed by entering dotnet --info at a system command prompt. You can download a .NET SDK version specific to your operating system from https://dotnet.microsoft.com/download.

Data Management

To exchange data between the deployed MATLAB code and the .NET application, use the MATLAB Data API for .NET. This API is also used by MATLAB Engine. For an overview, see Call MATLAB from .NET. For details, see:

Handle Class Support

When generating a .NET assembly from a MATLAB class that inherits from a MATLAB handle class, the following functionality is now supported:

  • Copy Behavior: The generated .NET assembly replicates MATLAB handle class copy behavior. In MATLAB, handle objects are reference types, which means that when you copy these objects, both the original and the new variable refer to the same object. This behavior is now preserved in the C# translation when you deploy to .NET.

  • Relational Operators: C# objects created based on the MATLAB handle class definitions in the .NET assembly support relational operations. This allows for the use of standard relational operators (==, !=, <, >, <=, >=) in C#, similar to their functionality in MATLAB.

  • isvalid Method Support: The .NET assembly includes support for the isvalid method, consistent with MATLAB handle class behavior. In C#, this method checks if the objects created from MATLAB handle classes are still valid or have been deleted, mirroring the functionality found in MATLAB.

  • delete Method Support: The delete method is also supported in the .NET assembly for C# objects derived from MATLAB handle classes. This function enables the deletion of these objects in a way that is aligned with how deletion is handled in MATLAB.

Create MATLAB Class that Inherits from MATLAB Handle Class

Create a MATLAB file named BankAccount.m with the following code:

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

Established MATLAB users may find it unconventional to see a properties block in a class and an arguments block in a method or function, each detailed with data type information. Both blocks let you represent C# data types with an equivalent MATLAB type. For instance, if your C# application employs a double data type representing a value, you can now represent that in MATLAB as a double. You can also specify a MATLAB object as an argument or property type. For example, the checkBalance method specifies BankAccount as the type for the input argument and double as the type for the output argument.

Test the MATLAB class at the command prompt.

%% 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

Create .NET Assembly Using compiler.build.dotNETAssembly

Create a code archive (.ctf file), from the MATLAB function using the compiler.build.dotNETAssembly function.

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

Although supplying an assembly name via the AssemblyName property isn't mandatory, it's highly recommended. Doing so results in a cleaner namespace for the generated .NET assembly and C# file. In its absence, a root namespace named example is automatically appended to the sub-namespace, leading to a cluttered and potentially confusing namespace structure.

The class produces a suite of files, as enumerated below, and places them in the specified output directory. Among these, the key files utilized during the integration process are the code archive (.ctf file) containing the MATLAB code, a C# (.cs) code file, and a .NET assembly (.dll file). For information on the other files, see Files Generated After Packaging MATLAB Functions.

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

To finalize integration, you can choose one of two options:

  • Use the Banking.ctf code archive file in conjunction with the BankAccount.cs C# code file.

  • Use the Banking.ctf code archive file in conjunction with the Banking.dll .NET assembly file.

Upon inspection, you notice that the function also generates a Banking.csproj project file. This file is generated specifically to create the corresponding Banking.dll .NET assembly file. However, it should not be mistaken as a template for your .NET project and must not be used in that context.

This example employs the first integration option to illustrate type mapping mechanics. Relevant guidance for using the second option is interjected at pertinent stages of the workflow.

You can inspect the content of the C# code file below:

 BankAccount.cs

Mapping Between MATLAB Class and Generated C# Class

MATLAB Class ElementC# Class Elementa
BankAccount class definition[MATLABClass("BankAccount")]
BankAccount constructorpublic BankAccount(MATLABProvider _matlab, double initialBalance)
deposit methodpublic void deposit(double amount)
withdraw methodpublic void withdraw(double amount)
checkBalance method

public void checkBalance()

public void checkBalance(out double bal)

Relational operators inherited from MATLAB handle class

  • ==

  • !=

  • <

  • >

  • <=

  • >=

public static bool operator ==

public static bool operator !=

public static bool operator

public static bool operator >

public static bool operator <=

public static bool operator >=

delete method inherited from MATLAB handle classpublic void delete()
isvalid method inherited from MATLAB handle classpublic 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.

Integrate MATLAB Code into .NET Application

You can finalize the integration process in your preferred C# development environment, including a text editor along with the .NET SDK Command Line API, or alternatives such as Microsoft Visual Studio on Windows and macOS. This example shows you how to complete the integration using both options. For details, see Setting Up .NET Development Environment.

Use .NET SDK Command Line API to Build Application

If you are using Microsoft Visual Studio, see Use Microsoft Visual Studio to Build Application (Windows).

  1. Open the command prompt in Windows and navigate to the work folder being used in this example.

  2. At the command line, enter:

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

    This command creates a folder named BankAccountConsoleApp that contains the following:

    • obj folder

    • BankAccountConsoleApp.csproj project file

    • Program.cs C# source file

  3. Copy the following files produced by the compiler.build.dotNETAssembly function to the project folder created by dotnet new, alongside the Program.cs C# application code file:

    • .cs C# wrapper files from the ...\work\output\strongly_typed_interface\ directory.

    • Banking.ctf code archive from the ...\work\output directory.

  4. Edit the project to add assembly dependencies and the Banking.ctf code archive file generated by the compiler.build.dotNETAssembly function.

    1. Open the project file in a text editor and include the following assemblies using a <Reference> tag within the <ItemGroup> tag of the project:

      • MathWorks.MATLAB.Runtime.dll

      • MathWorks.MATLAB.Types.dll

       Windows Paths

       Linux and macOS Paths

      Note

      If you use the Banking.dll .NET assembly generated by the compiler.build.dotNETAssembly function instead of the C# code file, include that as a reference within the same <ItemGroup> tag.

    2. Include the Banking.ctf code archive file as a content file to the project.

      • Add the Banking.ctf code archive file as a content file within the <ItemGroup> tag.

      • Add the tag CopyToOutputDirectory and set it to Always. This step ensures that the Banking.ctf file is copied to the output folder during the build process. This means that when you build your project, this file is in the same directory as your built .exe file.

      • Add the tag CopyToPublishDirectory and set it to Always. This step ensures that the Banking.ctf file is copied to the cross-platform folder to which this project is published.

    Once you add the assembly dependencies and include Banking.ctf as a content file, your project file looks like the following:

     BankAccountConsoleApp.csproj (Windows)

     BankAccountConsoleApp.csproj (Linux)

     BankAccountConsoleApp.csproj (macOS)

    Note

    If you choose to use the Banking.dll .NET assembly—generated by compiler.build.dotNETAssembly—over the C# code file, remember to uncomment the reference tags to the Banking.dll in the project file. This change ensures your project correctly uses the .dll file.

  5. Replace the code in the Program.cs C# file with the following code:

     Program.cs

    Note

    While developing and operating on macOS systems, transition the code from the Main method into a new function named MainFunc. Subsequently, invoke MATLABRuntime.SetupMacRunLoopAndRun from within the Main method and pass MainFunc along with the command-line arguments as parameters. MATLABRuntime.SetupMacRunLoopAndRun is integral for macOS environments because it lets MATLAB interact with the Core Foundation Run Loop (CFRunLoop), a macOS-specific mechanism for handling events such as user inputs or timer events. For details, see MathWorks.MATLAB.Runtime.MATLABRuntime.

  6. At the command line, build your project by entering:

    dotnet build BankAccountConsoleApp.csproj

Run C# Application

For testing purposes, you can run the application from MATLAB command prompt. This does not require a MATLAB Runtime installation.

At the MATLAB command prompt, navigate to the directory containing the executable, and run your application by entering:

!dotnet run

The application displays the mean values.

Balance after deposit:  150
Balance after withdrawal:  120
Balance from joint account:  140
Balance original account:  140

Note

When you're ready to deploy this application, ensure the target system has MATLAB Runtime installed. For details, see Install and Configure MATLAB Runtime. On Linux and macOS systems, you must set the LD_LIBRARY_PATH and DYLD_LIBRARY_PATH runtime paths respectively, prior to running your application. For details, see Set MATLAB Runtime Path for Deployment.

Use Microsoft Visual Studio to Build Application (Windows)

  1. Open Microsoft Visual Studio and create a C# Console App named BankAccountConsoleApp.

  2. Choose .NET 6.0 (Long-term support) as the framework.

  3. Swap out the default-generated source code in the Program.cs file with the specific source code provided in the Program.cs file found on this example page.

  4. Choose one of two options:

    • To incorporate the BankAccount.cs C# code file generated by the compiler.build.dotNETAssembly function, navigate to Solution Explorer, right-click your project, and select Add > Existing Item. Use the dialog box to find and add the BankAccount.cs C# code file.

    • If you prefer to use the Banking.dll .NET assembly produced by the compiler.build.dotNETAssembly function, right-click your solution in Solution Explorer and choose Edit Project File. Here, you'll need to add a reference to the Banking.dll file within the existing <ItemGroup> tag.

    View one of the above-listed project files as a reference.

  5. Add the following assembly dependencies:

    • MathWorks.MATLAB.Runtime.dll

    • MathWorks.MATLAB.Types.dll

     Location of Assembly Dependencies

  6. Add the Banking.ctf code archive file as a content file to the project. Right-click your project in Solution Explorer and select Add > Existing Item. In the dialog box, browse for the file and add the file.

  7. Right-click the Banking.ctf file in Solution Explorer and select Properties. In the Properties window, set Build Action to Content and Copy to Output Directory to Copy always.

  8. Right-click your project in Solution Explorer and select Edit Project File. The BankAccountConsoleApp.csproj project file opens in the editor. Add the <CopyToPublishDirectory> tag right below the <CopyToOutputDirectory> tag and set it to Always. The edited portion of the BankAccountConsoleApp.csproj project file looks as follows:

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

  9. On the menu bar, choose Build and choose Build Solution to build the application within Visual Studio.

    The build process generates an executable named BankAccountConsoleApp.exe.

  10. Run the application from Visual Studio by pressing Ctrl+F5. Alternatively, you can execute the generated executable from a system terminal:

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

    The application returns the same output as the sample MATLAB code.

    Balance after deposit:  150
    Balance after withdrawal:  120
    Balance from joint account:  140
    Balance original account:  140

    Tip

    • If you are unable to build your application, change the solution platform from Any CPU to x64.

    • If you are unable to run your application from Visual Studio, open the Developer Command Prompt for Visual Studio and start Visual Studio by entering devenv /useenv. Then, open your project and run your application.

See Also

| |

Related Topics