Main Content

Implement Type-Safe Interface and Integrate into .NET Application

This example shows how to implement a type-safe interface and integrate it into a .NET application.

Type-safe interfaces allow you to work directly with familiar native data types instead of using the MWArray API. Adding a type-safe interface to a .NET assembly creates an additional set of methods that accept and return native .NET types.

Write and Test Your MATLAB Code

Create your MATLAB® program and then test the code before implementing a type-safe interface. The functions in your MATLAB program must match the declarations in your native .NET interface.

For this example, save the following code as multiply.m. The function returns the multiplication of the inputs x and y.

function z = multiply(x,y)
z = x * y;

Test the function at the MATLAB command prompt.

multiply([1 4 7; 2 5 8; 3 6 9],[1 4 7; 2 5 8; 3 6 9])
 ans =

    30    66   102
    36    81   126
    42    96   150

Implement Type-Safe Interface

After you write and test your MATLAB code, develop a .NET type-safe interface in either C# or Visual Basic®. This example uses provided C# source code for the interface.

  1. Open Microsoft® Visual Studio® and create a new Class Library (.NET Framework) project named IMultiply.

  2. In the Solution Explorer window, rename the Class1.cs file to IMultiply.cs. In this file, you write source code for the type-safe interface that accesses the component.

    In this example, the IMultiply interface is written in C# and specifies three overloads of multiply:

    using System;
    
    public interface IMultiply
    {
        // Scalar multiplication
        System.Double multiply(System.Double x, System.Double y);
    
        // Multiply vector by a scalar, return a vector
        System.Double[] multiply(System.Double[] x, System.Double y);
    
        // Matrix multiplication
        System.Double[,] multiply(System.Double[,] x, System.Double[,] y);
    }

    Each method in the interface must exactly match a deployed MATLAB function.

    All methods have two inputs and one output (to match the MATLAB multiply function), though the parameter data type varies.

  3. Go to Build and then Configuration Manager, and change the platform from Any CPU to x64.

  4. Build the project with Microsoft Visual Studio.

    The file IMultiply.dll is generated in the build folder.

This example assumes your assembly contains only IMultiply. Realistically, it is more likely that the type-safe interface will already be part of a compiled assembly. The assembly can be compiled even before the MATLAB function is written.

Create .NET Assembly Using Library Compiler App

Generate the type-safe interface with the .NET assembly using the Library Compiler app. Alternatively, if you want to create a .NET assembly from the MATLAB command window using a programmatic approach, see Create .NET Assembly Using compiler.build.dotNETAssembly.

  1. Create a Library Compiler project and select .NET Assembly from the Type list.

  2. Specify the following values:

    FieldValue
    Library NameMultiply
    Class NameArithmetic
    File to Compilemultiply.m

  3. Expand the Additional Runtime Settings section.

  4. In the Type-Safe API section, do the following:

    1. Select Enable Type-Safe API.

    2. In the Interface assembly field, specify the location of the type-safe interface assembly IMultiply.dll that you built.

    3. Select the IMultiply interface from the .NET interface drop-down box.

    4. Leave the Namespace field blank.

    5. Specify the Arithmetic class in the Wrapped Class field.

  5. Click the Package button to build the project.

Create .NET Assembly Using compiler.build.dotNETAssembly

As an alternative to the Library Compiler app, you can generate the type-safe interface using a programmatic approach using the following steps. If you have already created an assembly using the Library Compiler, see Integrate .NET Assembly into .NET Application.

  1. Build the .NET assembly using the compiler.build.dotNETAssembly function. Use name-value arguments to specify the assembly name and class name.

    compiler.build.dotNETAssembly('multiply.m', ...
        'AssemblyName','Multiply', ...
        'ClassName','Arithmetic');
    
  2. Navigate to the generated MultiplydotNETAssembly folder.

  3. Generate the type-safe interface by using the ntswrap command from MATLAB:

    ntswrap('-c','Multiply.Arithmetic', ...
            '-a','IMultiply.dll', ...
            '-i','IMultiply');

    Not all arguments are compatible with each other. See ntswrap for details on all command options.

    Tip

    If the IMultiply.dll assembly is not in the current folder, specify the full path.

    This command generates the assembly ArithmeticIMultiply.dll that contains a type-safe API for the MATLAB Compiler SDK™ class Arithmetic in the namespace MultiplyNative.

Integrate .NET Assembly into .NET Application

After creating your .NET assembly, you can integrate it into any .NET application. You can use this example .NET application code as a guide to write your own .NET application.

Compile the .NET program using Microsoft Visual Studio by doing the following steps:

  1. Open Microsoft Visual Studio and create a C# Console App (.NET Framework) called MultiplyApp.

  2. Copy the following source code into the generated Program.cs in your project:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace MultiplyApp
    {
        class Program
        {
            delegate String VectorToString<T>(IEnumerable<T> v);
            delegate IEnumerable<String> MatrixToString<T>(T[,] m);
    
            static void Main(string[] args)
            {
                Console.WriteLine("\nStarting application...\n");
                
                //Create an instance of the Type-safe API
                IMultiply m = new ArithmeticIMultiply();
                
                // Scalar multiplication
                double x = 17, y = 3.14159;
                double z = m.multiply(x, y);
                System.Console.WriteLine("{0} * {1} = {2}\n", x, y, z);
    
                // Vector times scalar
                double[] v = new double[] { 2.5, 81, 64 };
                double s = 11;
                double[] d = m.multiply(v, s);
    
                VectorToString<double> vec2str = (vec =>
                  vec.Select(n => n.ToString()).Aggregate((str, next) => str + " " + next));
    
                System.Console.WriteLine("[ {0} ] * {1} = [ {2} ]\n",
                    vec2str(v), s, vec2str(d));
    
                // Matrix multiplication
                double[,] magic = new double[,]{  // 3x3 magic square
                         { 8, 1, 6 },
                         { 3, 5, 7 },
                         { 4, 9, 2 } };
                double[,] squareSquared = m.multiply(magic, magic);
    
                MatrixToString<double> mat2str = mat =>
                    mat.EnumerateRows<double>().Select(r => vec2str(r));
    
                PrintParallel(mat2str(magic), " * ".Select(c => c.ToString()),
                              mat2str(magic), " = ".Select(c => c.ToString()),
                              mat2str(squareSquared));
    
                Console.WriteLine("\nClosing application...");
            }
    
            public static void PrintParallel<T>(params IEnumerable<T>[] sources)
            {
                int max = sources.Select(s => s.Count()).Max();
                for (int i = 0; i < max; i++)
                {
                    foreach (var src in sources)
                        System.Console.Write("{0} ", src.ElementAt(i));
                    System.Console.WriteLine();
                }
            }
        }
        public static class ArrayExtensions
        {
            public static IEnumerable<IEnumerable<T>> EnumerateRows<T>(this Array a)
            {
                return Enumerable.Range(0, a.GetLength(1)).Select(row =>
                    a.ToIEnumerable<T>().Skip(row * a.GetLength(0)).Take(a.GetLength(0)));
            }
    
            public static IEnumerable<T> ToIEnumerable<T>(this Array a)
            {
                foreach (var item in a)
                    yield return (T)item;
            }
    
        }
    }
    
  3. Add references in the project to the following files.

    This reference:Defines:
    IMultiply.dllThe .NET native type interface assembly IMultiply
    ArithmeticIMultiply.dllThe generated type-safe API
    MultiplyNative.dllThe generated .NET assembly

    Note

    Unlike other .NET deployment scenarios, you do not need to reference MWArray.dll in the server program source code. The MWArray data types are hidden behind the type-safe API in ArithmeticIMultiply.

  4. Go to Build and then Configuration Manager, and change the platform from Any CPU to x64.

  5. Compile and run the program with Microsoft Visual Studio.

    The program displays the following output:

    Starting application...
    
    17 * 3.14159 = 53.40703
    
    [ 2.5 81 64 ] * 11 = [ 27.5 891 704 ]
    
    8 1 6   8 1 6   91 67 67
    3 5 7 * 3 5 7 = 67 91 67
    4 9 2   4 9 2   67 67 91
    
    Closing application...

Tips

  • In a MATLAB function, declaration outputs appear before inputs. For example, in the multiply function, the output z appears before the inputs x and y. This ordering is not required for .NET interface functions. Inputs may appear before or after outputs, or the two may be mixed together.

  • MATLAB Compiler SDK matches .NET interface functions to public MATLAB functions by function name and argument count. In the multiply example, both the .NET interface function and the MATLAB function must be named multiply, and both functions must have an equal number of arguments defined.

  • The number and relative order of input and output arguments is critical.

    • In evaluating parameter order, only the order of like parameters (inputs or outputs) is considered, regardless of where they appear in the parameter list.

    • A function in the interface may have fewer inputs than its corresponding MATLAB function, but not more.

  • Argument mapping occurs according to argument order rather than argument name.

  • The function return value, if specified, counts as the first output.

  • You must use out parameters for multiple outputs.

    • Alternately, the ref parameter can be used for out, as ref and out are synonymous.

  • MATLAB does not support overloading of functions. Thus, all user-supplied overloads of a function with a given name will map to a function generated by MATLAB Compiler SDK.

See .NET Types to MATLAB Types for complete guidelines in managing data conversion with type-safe interfaces.

See Also

|

Related Topics