实现类型安全接口并集成到 .NET 应用程序中
此示例说明如何实现类型安全接口并将其集成到 .NET 应用程序中。
类型安全接口允许您直接使用熟悉的本机数据类型,而不必使用 MWArray
API。向 .NET 程序集添加类型安全接口会创建一组额外的方法,用于接受和返回本机 .NET 类型。
编写并测试您的 MATLAB 代码
创建 MATLAB® 程序,然后在实现类型安全接口之前测试代码。MATLAB 程序中的函数必须与本机 .NET 接口中的声明相匹配。
对于此示例,将以下代码保存为 multiply.m
。该函数返回输入 x
和 y
的乘积。
function z = multiply(x,y)
z = x * y;
在 MATLAB 命令提示符下测试该函数。
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
实现类型安全接口
编写并测试 MATLAB 代码后,使用 C# 或 Visual Basic® 开发 .NET 类型安全接口。此示例使用提供的 C# 源代码作为界面。
打开 Microsoft® Visual Studio® 并创建一个名为
IMultiply
的新 Class Library (.NET Framework) 工程。在解决方案资源管理器窗口中,将
Class1.cs
文件重命名为IMultiply.cs
。在此文件中,您可以为访问组件的类型安全接口编写源代码。在此示例中,
IMultiply
接口用 C# 编写,并指定了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); }
接口中的每个方法必须与部署的 MATLAB 函数完全匹配。
所有方法都有两个输入和一个输出(以匹配 MATLAB
multiply
函数),但参数数据类型各不相同。转到 Build,然后转到 Configuration Manager,并将平台从 Any CPU 更改为 x64。
使用 Microsoft Visual Studio 构建工程。
在构建文件夹中生成文件
IMultiply.dll
。
此示例假设您的程序集仅包含 IMultiply
。实际上,类型安全接口更有可能已经是已编译程序集的一部分。甚至可以在编写 MATLAB 函数之前编译汇编。
使用 .NET 程序集编译器创建 .NET 程序集
使用 .NET 程序集编译器通过 .NET 程序集生成类型安全的接口。或者,如果您想使用编程方法从 MATLAB 命令行窗口创建 .NET 程序集,请参阅使用 compiler.build.dotNETAssembly 创建 .NET 程序集。
创建一个 .NET 组件编译器工程,从类型列表中选择 .NET 程序集。
指定以下值:
字段 值 库名称 Multiply
类名 Arithmetic
要编译的文件 multiply.m
展开其他运行时设置部分。
在类型安全的 API 部分中,执行以下操作:
选择启用类型安全的 API。
在接口程序集字段中,指定您构建的类型安全接口程序集
IMultiply.dll
的位置。从 .NET 接口下拉框中选择
IMultiply
接口。将命名空间字段留空。
在包装的类字段中指定
Arithmetic
类。
点击打包按钮来构建工程。
使用 compiler.build.dotNETAssembly
创建 .NET 程序集
作为 .NET 程序集编译器的替代方案,您可以通过以下步骤使用程序化方法生成类型安全的接口。如果您已经使用 .NET 程序集编译器创建了组件,请参阅将 .NET 程序集集成到 .NET 应用程序中。
使用
compiler.build.dotNETAssembly
函数编译 .NET 程序集。使用名称-值参量指定程序集名称和类名。compiler.build.dotNETAssembly('multiply.m', ... 'AssemblyName','Multiply', ... 'ClassName','Arithmetic');
导航到生成的
MultiplydotNETAssembly
文件夹。使用 MATLAB 中的
ntswrap
命令生成类型安全接口:ntswrap('-c','Multiply.Arithmetic', ... '-a','IMultiply.dll', ... '-i','IMultiply');
并非所有参量都是互相兼容的。有关所有命令选项的详细信息,请参阅
ntswrap
。提示
如果
IMultiply.dll
程序集不在当前文件夹中,请指定完整路径。此命令生成程序集
ArithmeticIMultiply.dll
,其中包含命名空间Arithmetic
中 MATLAB Compiler SDK™ 类MultiplyNative
的类型安全 API。
将 .NET 程序集集成到 .NET 应用程序中
创建 .NET 程序集后,您可以将其集成到任何 .NET 应用程序中。您可以使用此示例 .NET 应用程序代码作为指南来编写您自己的 .NET 应用程序。
按照以下步骤使用 Microsoft Visual Studio 编译 .NET 程序:
打开 Microsoft Visual Studio 并创建一个名为
MultiplyApp
的 C# Console App (.NET Framework)。将以下源代码复制到工程中生成的
Program.cs
中: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; } } }
在工程中添加对以下文件的引用。
此引用: 定义: IMultiply.dll
.NET 本机类型接口程序集 IMultiply
ArithmeticIMultiply.dll
生成的类型安全 API MultiplyNative.dll
生成的 .NET 程序集 注意
与其他 .NET 部署场景不同,您不需要在服务器程序源代码中引用
MWArray.dll
。MWArray
数据类型隐藏在ArithmeticIMultiply
中类型安全的 API 后面。转到 Build,然后转到 Configuration Manager,并将平台从 Any CPU 更改为 x64。
使用 Microsoft Visual Studio 编译并运行该程序。
该程序显示以下输出:
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...
提示
在 MATLAB 函数中,声明输出出现在输入之前。例如,在
multiply
函数中,输出z
出现在输入x
和y
之前。.NET 接口函数不需要这种排序。输入可能出现在输出之前或之后,或者两者混合在一起。MATLAB Compiler SDK 根据函数名称和参量数量将 .NET 接口函数与公共 MATLAB 函数进行匹配。在
multiply
示例中,.NET 接口函数和 MATLAB 函数都必须命名为multiply
,并且两个函数必须定义相同数量的参量。输入和输出参量的数量和相对顺序至关重要。
在评估参数顺序时,只考虑类似参数(输入或输出)的顺序,而不管它们出现在参数列表中的什么位置。
接口中的函数的输入可能比其对应的 MATLAB 函数少,但不会多。
参量映射根据参量顺序而不是参量名称进行。
如果指定了函数返回值,则该值算作第一个输出。
您必须使用
out
参数来执行多个输出。另外,
ref
参数可用于out
,因为ref
和out
是同义词。
MATLAB 不支持函数重载。因此,具有给定名称的函数的所有用户提供的重载都将映射到由 MATLAB Compiler SDK 生成的函数。
看.NET 类型到 MATLAB 类型有关使用类型安全接口管理数据转换的完整指南。
另请参阅
compiler.build.dotNETAssembly
| ntswrap