尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Csharp快速上手(框架搭建+实战:矩阵卷积计算)

发布时间:2026/9/24 17:18:56

资讯中心
01
ARTICLE

Csharp快速上手(框架搭建+实战:矩阵卷积计算)

Csharp快速上手(框架搭建+实战:矩阵卷积计算)
1.基础控件1.1 工具箱——集成各种控件控件在视图底下的工具箱1.2 ToolStrip控件——菜单栏这里主要说Button按钮正常点击是这个样子 只有图片 没有文字 右键 打开属性选择ImageAndTextImage里可以更改图片 Text里可以改文字1.3 OpenFileDialog打开文件我们现在把之前创建的Button新增一个打开文件的功能我们这里给控件改一个名字双击Button会自动跳转到代码界面 我们可以将点击这个Button后触发的事件写进这里面同时Button控件也新增了一个事件如果要删除Button的点击效果 我们要从事件里面删除开始编写代码这是 C# WinForms 中OpenFileDialog组件的标准交互逻辑弹出文件选择对话框当用户点击「确定OK」按钮后执行{ }内的业务代码代码运行效果如下 不过此刻打开后不会发生任何情况 因为{}里面什么东西都没有我们先写一些基础代码操作获取选中的文件路径private void OpenFile_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() DialogResult.OK) { string filePath openFileDialog1.FileName; // 弹出系统对话框显示文字内容 MessageBox.Show($选中的文件路径{filePath}, 文件选择成功); } }运行效果1.4 SaveFileDialog保存文件SaveFileDialog是 WinForm 框架提供的系统原生「另存为」对话框组件它的作用是为用户提供可视化的保存路径选择、文件名输入、文件类型切换界面最终将用户选定的完整文件路径返回给程序。它本身不执行文件写入实际保存逻辑需要开发者通过文件 IO 代码实现。同样的操作我们来新建一个Button 并重命名为SaveFile我们来创建一个点击事件 并编写代码private void SaveFile_Click(object sender, EventArgs e) { if(saveFileDialog1.ShowDialog()DialogResult.OK) { string filePath saveFileDialog1.FileName; if(filePath!null) { } } }运行效果点击确定后 不会有任何事情发生 因为我们的代码里什么都没写1.5 RichTextBox展示与编辑文本RichTextBox是 WinForm 中的高级文本编辑控件支持字体 / 颜色 / 字号格式化、段落排版、嵌入图片、超链接识别等富文本功能能力远强于普通TextBox。从工具箱拖入窗体后默认名称为richTextBox1常用于实现文本编辑器、日志展示、富文本文档查看等场景。现在其实我们就可以根据这几个控件编写一个小程序private void OpenFile_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() DialogResult.OK) { string filePath openFileDialog1.FileName; if(filePath ! null) { richTextBox1.Text filePath; } } } private void SaveFile_Click(object sender, EventArgs e) { if(saveFileDialog1.ShowDialog() DialogResult.OK) { string filePath saveFileDialog1.FileName; if(filePath!null) { var writer new StreamWriter(filePath); writer.WriteLine(richTextBox1.Text); writer.Close(); } } }1. OpenFile_Click —— 打开文件按钮事件点击对应按钮后会弹出系统标准的「打开文件」对话框若用户在对话框中选中文件并点击「确定」会获取该文件的完整路径将这个文件路径字符串直接显示在richTextBox1富文本框中该方法不会读取文件里的实际内容仅展示路径。2. SaveFile_Click —— 保存文件按钮事件点击对应按钮后会弹出系统标准的「保存文件」对话框若用户在对话框中选择保存位置、输入文件名并点击「确定」会得到目标保存路径创建StreamWriter文件写入流把richTextBox1里当前的全部文本内容写入到该路径的文件中写入完成后调用Close()手动关闭文件流。运行效果代码这里 说一下写入方法Write和WriteLine是TextWriterStreamWriter的基类的核心写入方法唯一本质区别是写入完成后是否自动追加换行符其他重载规则、支持的数据类型完全一致。1. Write () 方法行为仅将指定内容字符串、字符、数字等写入流不添加任何额外字符。效果写入内容完全精确不会凭空多出换行、空格。适用场景需要严格匹配原始内容、手动控制换行、拼接文本的场景。2. WriteLine () 方法行为写入指定内容后自动在末尾追加一个系统默认换行符Windows 环境下是\r\n对应Environment.NewLine。特殊用法不带参数的WriteLine()效果是只写入一个换行符。适用场景逐行写入日志、按行输出内容需要自动换行的场景。var writer new StreamWriter(filePath);1.var—— 隐式类型推断关键字var是 C# 的语法糖作用是让编译器根据等号右边的表达式自动推导出变量的具体类型不用手动写出完整类型名。这里右边是new StreamWriter(...)所以编译器会自动推断writer的类型就是StreamWriter。它和手写StreamWriter writer new StreamWriter(filePath);完全等价编译后没有任何区别也不影响性能。2.writer—— 变量名就是你给这个StreamWriter对象起的名字通过它你才能后续调用写入、关闭等方法比如writer.Write()、writer.Close()。3.new StreamWriter(filePath)—— 核心功能本体这才是真正创建文件写入能力的部分StreamWriter是 .NET 中System.IO命名空间下的类专门用来以文本形式向文件写入字符数据。new StreamWriter(filePath)会做两件事打开你指定路径的文件如果文件不存在就自动创建如果文件已存在默认会清空并覆盖原有内容。在内存和文件之间建立一个 “写入流通道”后续你调用写入方法时数据会通过这个通道写到磁盘文件里。2.我个人喜欢的界面风格上面那些基础控件会了之后 我们其实就能做不少基础的程序 无非就是写写算法 读取数据之类的麻烦一点罢了 但我认为一个好的程序 它的界面也要比较好看2.1 StatusStrip状态栏控件这个控件功能比较多 但程序不复杂的时候可以当个花瓶用用StatusLabel2.2 SplitContainer 分割容器控件核心说明基础功能它会将一块完整的显示区域拆分为两个独立的子面板Panel1与Panel2中间带有一条可拖拽的分隔条用户可以自由拖动分隔条调整两个面板的尺寸占比两个面板内部都可以独立嵌套放置其他控件。布局特性支持两种分割方向Vertical垂直分割左右双面板、Horizontal水平分割上下双面板。支持停靠Dock填充常作为窗体主布局容器自动适配窗口大小变化。可通过属性锁定分隔条、设置分隔条宽度、定义最小面板尺寸避免面板被拖拽到过小。布局效果2.3 GroupBox 分组框控件基础功能它的核心作用是为一组功能关联的控件提供带标题的边框容器从视觉和逻辑上对界面控件进行分组归类让用户能直观区分不同功能区域避免界面控件杂乱。主要特性属于容器控件内部可嵌套放置文本框、单选框、按钮等任意子控件移动 GroupBox 时内部控件会同步位移方便批量布局管理。通过Text属性自定义分组标题比如 “基本信息”“高级设置”也可调整边框样式、字体、背景色匹配整体界面风格。常和单选按钮RadioButton配合使用同一个 GroupBox 内的单选按钮会自动形成一组互斥选项。效果展示这里我们说一下Dock这个功能Dock属性选择Fill 可以填满父容器改个名字 调个色BackColor插入RichTextBox后界面整体大概就是这样当然一般我是以表格的形式去呈现原始数据的 这以后再说3.实战一矩阵卷积计算3.1 Matrix.cs我觉得要先构建一个矩阵数据结构新建一个文件 专门用来构建Matrixnamespace WindowsFormsApp2 { internal class Matrix { public double[,] data; public Matrix() { data new double[,] { }; } } }这段是 C# 语言编写的代码归属于 WindowsFormsApp2 这个命名空间定义了一个仅在当前项目内部可用的 Matrix 矩阵类。命名空间的作用是对代码进行分类组织避免不同模块的类名出现冲突。类前面的 internal 是访问修饰符代表这个 Matrix 类只能在当前这个 WinForm 项目编译生成的程序集内部被访问使用外部项目引用时无法调用这个类。类内部定义了一个 public 修饰的二维双精度浮点型数组字段 data它是这个矩阵类的核心数据载体用来存放矩阵里的所有数值元素。接下来的 public Matrix () 是这个类的无参构造函数每当我们创建一个新的 Matrix 对象时这个方法就会自动执行它的作用是对 data 字段进行初始化在对象创建时默认给 data 赋值为一个长度为 0 的空二维数组让新生成的矩阵实例初始处于空数据的状态。内置一个求和函数Sum()在Matrix类里面public double Sum() { double result 0; for(int i0; idata.GetLength(0); i) { for(int j0; jdata.GetLength(1); j) { result data[i,j]; } } return result; }完整代码internal class Matrix { public double[,] data; public Matrix() { data new double[,] { }; } public double Sum() { double result 0; for(int i0; idata.GetLength(0); i) { for(int j0; jdata.GetLength(1); j) { result data[i,j]; } } return result; } }3.2 FileHelper.cs用于帮助读取文档 并将读取结果转换到我们的Matrix数据结构public static double[,] ReadM(string filePath) { int n 3; var Result new double[3,3]; var readernew StreamReader(filePath); try { for (int i 0; i n; i) { string data reader.ReadLine(); for (int j 0; j 3; j) { var buf data.Split(\t); Result[i,j]double.Parse(buf[j]); } } } catch (Exception ex) { throw ex; } reader.Close(); return Result; } public static double[,] ReadN(string filePath) { int n 10; var Result new double[10, 10]; var reader new StreamReader(filePath); try { for (int i 0; i n; i) { string data reader.ReadLine(); for (int j 0; j n; j) { var buf data.Split(\t); Result[i, j] double.Parse(buf[j]); } } } catch (Exception ex) { throw ex; } reader.Close(); return Result; }这个代码很粗糙 而且复用性很差 只能针对一种特殊的数据结构矩阵每一行相邻俩个元素以制表符分隔开来 但方便理解这里说一下Read和ReadLine 1. ReadLine 实现 ReadM 读取矩阵 矩阵维度3行 × 3列 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 2. ReadLine 逐行读取原始效果 第1行[1.1 2.2 3.3]文本长度9 第2行[4.4 5.5 6.6]文本长度9 第3行[7.7 8.8 9.9]文本长度9 读到文件末尾返回 null 3. Read 逐字符读取原始效果 第1个字符[1]ASCII码49 第2个字符[.]ASCII码46 第3个字符[1]ASCII码49 第4个字符[空格]ASCII码32 第5个字符[2]ASCII码50 第6个字符[.]ASCII码46 第7个字符[2]ASCII码50 第8个字符[空格]ASCII码32 第9个字符[3]ASCII码51 第10个字符[.]ASCII码46 第11个字符[3]ASCII码51 第12个字符[\r]ASCII码13 第13个字符[\n]ASCII码10 第14个字符[4]ASCII码52 ...中间字符省略 第38个字符[9]ASCII码57 第39个字符[.]ASCII码46 第40个字符[9]ASCII码57 读到文件末尾返回 -1接下来我们可以直接写算法了 可以先直接跳转到3.3 Algo.cs看完算法的设计后 我们应该做的是读取数据——计算——输出结果编写结果输出代码public static string WriteData(Matrix m) { string Result ; for (int i 0; i m.data.GetLength(0); i) { for (int j 0; j m.data.GetLength(1); j) { Result Result m.data[i, j].ToString() \t; } Result Result \n; } return Result; }这里是将我们读取的数据转换为字符串public static string WriteResult(Matrix m) { string Result ; for (int i 0; i m.data.GetLength(0); i) { for (int j 0; j m.data.GetLength(1); j) { Result Result ${m.data[i,j]:f2}\t; } Result Result \n; } return Result; }这里我们将计算结果转换为字符串3.3 Algo.cs只实现算法1internal class Algo { public double[,] Algo1(Matrix M, Matrix N) { var Result new double[10, 10]; for(int i0;iN.data.GetLength(0);i) { for(int j0;jN.data.GetLength(1);j) { Result[i, j] InAlgo1(i, j, M, N); } } return Result; } public double InAlgo1(int I, int J, Matrix M, Matrix N) { double Result 0; int i_e 3; int j_e 3; double Mij 0; double Nij 0; double sum1 0;//分子 double sum2 0;//分母 for (int i 0; i i_e; i) { for (int j 0; j j_e; j) { if (I - i - 1 0 || J - j - 1 0 || I - i - 1 9 || J - j - 1 9) { Mij 0; } else { Mij M.data[i, j]; Nij N.data[I-i-1, J-j-1]; } sum1 sum1 Mij * Nij; sum2 sum2 Mij; } } Result sum1 / sum2; return Result; } }只要把算法的公式搞懂 对着敲代码就行 这里介绍俩个知识点data.GetLength(0)和data.GetLength(1data.GetLength(0)获取矩阵的行数。data.GetLength(1)获取矩阵的列数。var Result new double[10, 10];还有这个地方要强调一下这里不能像定义Matrix类一样 初始定义一个0行0列的二维矩阵必须要申明申请的空间大小不然访问时会说数组超限3.4 框架到这一步 我们就像拼一个机器人 现在已经把各个零件都拼好了 现在就是组装还记得我们的OpenFile_Click吗 现在我们要开始做些手脚了在做手脚前 我们先弄一下框架完整代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp2 { public partial class Form1 : Form { Matrix M new Matrix(); Matrix N new Matrix(); Matrix Result new Matrix(); string data ; public Form1() { InitializeComponent(); } private void OpenFile_Click(object sender, EventArgs e)//读取M矩阵 { if (openFileDialog1.ShowDialog() DialogResult.OK) { string filePath openFileDialog1.FileName; if(filePath ! null) { M.data FileHelper.ReadM(filePath); } data FileHelper.WriteData(M); richTextBox1.Text data; } } private void SaveFile_Click(object sender, EventArgs e)//保存文件 { if(saveFileDialog1.ShowDialog() DialogResult.OK) { string filePath saveFileDialog1.FileName; if(filePath!null) { } } } private void toolStripStatusLabel1_Click(object sender, EventArgs e) { } private void panel1_Paint(object sender, PaintEventArgs e) { } private void toolStripButton1_Click(object sender, EventArgs e)//读取N矩阵 { if (openFileDialog1.ShowDialog() DialogResult.OK) { string filePath openFileDialog1.FileName; if (filePath ! null) { N.data FileHelper.ReadN(filePath); } data FileHelper.WriteData(N); richTextBox1.Text data; } } private void toolStripButton2_Click(object sender, EventArgs e)//计算 { var algo new Algo(); Result.data algo.Algo1(M, N); richTextBox2.Text FileHelper.WriteResult(Result); } } }这里我们还没写文件保存的代码其实可以类推一下读取文件var Reader new StreamReader(filePath);同理var Writer new StreamWriter(filePath);private void SaveFile_Click(object sender, EventArgs e)//保存文件 { if(saveFileDialog1.ShowDialog() DialogResult.OK) { string filePath saveFileDialog1.FileName; if(filePath!null) { var writer new StreamWriter(filePath); writer.Write(richTextBox2.Text); writer.Close(); } } }运行结果如下
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。