C#上位机实战开发指南
第一章 C#和 Visual Stduio
1.1 .NET 时代
在.NET 之前,尤其是 20 世纪 90 年代,Windows 程序员几乎使用 VB,C 或者
C++。部分 C 和 C++开发者使用纯 Win32 Api,但是大多数人还是选择使用 MFC。
这些语言开发难度较大,底层代码复杂。21 世纪初期越来越多的开发者迫切需
要一个安全,集成度高,面向对象的开发框架。
2002 年,微软如期发布了.NET 框架的第一个版本,它具有如下几个特点:
●多平台
●安全性
●行业标准 使用标准通信协议,比如 HTTP,SOAP,JSON 等。
在 2016 年最新一期的编程语言排行榜中 C#.NET 位列第四,而且呈上升趋势。
可在任意计算机系统运行,包括服务器,台式机等。
提供更加安全的运行环境,即使有来源可疑的代码存在。
排行榜如图 1-1 所示。
图 1-1
1.2 C#的前世今生
C#是微软发布的一种面向对象,运行于.NET 之上的高级语言。也是微软近几
年主推的开发语言,可以说是微软.NET 框架的主角。只要具备一些 C 语言基础
就可以非常迅速的入门 C#开发,这也是我极力推荐使用 C#开发上位机的一个重
要原因。
1.3 难以置信的 Visual Studio 2015
Visual Studio 2015(以下简称 VS2015)是微软推出的开发环境,C#也是基于
此开发。相比较之前的版本,VS2015 具有更强大的调试功能,甚至集成了安卓,
IOS 等跨平台开发环境。作为一个强大的集成开发环境,VS2015 同时还能支持
STM32 单片机的编译。
具体教程请参看:http://www.openedv.com/thread-10273-1-1.html。
笔者认为 VS2015 是宇宙最强 IDE,完虐我们常用的单片机开发环境如 KEIL,
IAR 等。更多使用技巧就留给读者自己去发现吧。
1.4 VS2015 的安装与使用
第二章 C#语法基础
2.1 C#编程概述
本章将为上位机开发打基础,当然具有 C 语言或者单片机开发经验的同学也
可以跳过本章,直接进入第三章窗体程序的学习中。因为 C#和 C 语言在语法上
大致相同。本章只讲解一些与单片机 C 语言相差较大的部分,其余不再过多讲解。
代码分析也全部放在第三章以后。若想深入学习 C#,请参考专业入门书籍,推
荐《C#图解教程》(第四版)。
2.2 命名空间
在 C#中,命名空间提供了一种组织相关类和其它类型的方式。我理解的命名
空间就是一个集装箱,里面可以装下很多类和方法。其实我们也可以认为所谓的
命名空间相当于 C 语言中的头文件,只不过 include 变为了 using namespace。具
体的书写规范见代码清单 2-1。
代码清单 2-1:命名空间书写规范
//命名空间类似于头文件
//using ≈ include; Systerm ≈ xxxx.h
//用户自定义命名空间,相当于新定义一个头文件
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
1.
2.
3.
4.
5.
6.
7.
8.
9.
10. //一般情况下一个上位机工程对应一个新的命名空间
11. namespace Demo
12. {
13.
14.
15.
16.
17.
18.
19.
20.
21.
22. }
public partial class Form1 : Form
{
//构造函数,新建窗体工程时自动创建这段代码,可先忽略
public Form1()
{
InitializeComponent();
}
}
这段代码在新建工程之后由 VS2015 自动创建,第 1 到 7 行代码全都为系统
自带的命名空间。第 11 行为开发人员自定义的命名空间,之后的每一个上位机
项目都是一个自定义命名空间。
大概了解了 C#命名空间的书写格式规范后,我们再简单回忆一下 C 语言中头
文件的书写规范并比较二者的异同点,C 头文件书写格式见代码清单 2-2。
代码清单 2-2:C 头文件书写规范
TxBuffSize
256
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
1.
2.
3.
4.
5.
6.
7.
8.
9.
10. #define
11.
12.
13. #define
14.
15.
16. #define
17.
18.
19. void USART_Config(void);
20. void USART1_SendByte(uint8_t DataToSend);
21. void USART1_SendString(const char* StringToSend);
22. void USART1_SendBuff(uint8_t* DataToSend, uint8_t DataNum);
23.
24.
25. #endif
Debug_ON
1
DebugPutInfo(fmt,arg...) do{if(Debug_ON)printf(fmt,##arg);}while(0)
通过代码清单 2-2 我们很容易发现,C#的命名空间和 C 的头文件遵循一样的
规则,即要想使用某方法某函数则必须要包含方法所在的命名空间或者头文件。
这是相同点。不同点则表现在 C 语言在声明了头文件和函数接口后必须要在对应
的 C 文件中编写函数体后才可使用。C#则将省去了函数声明,直接即可编写对应
的函数体。
2.3 类
2.3.1 什么是类
在 C#开发中,类(class)至关重要。可以认为类是 C#一个很大的主题。关于它
的讨论将一直延续到本书结束。我们在单片机软件开发中设计数据结构时往往离
不开先设计结构体,其实类就相当于结构体,这也是面向对象的一个前提条件。
我们可以将类抽象成一个既能存储数据又能执行代码的数据结构。它包含数据成
员和函数成员,因此类对 C#代码的封装起着举足轻重的作用。
2.3.2 如何声明一个类
类的声明和结构体类似,即定义了一个新类的成员和特征。但是它并不创建
类的实例,相当于结构体声明后并不分配内存,只有在使用时声明后才会分配内
存一样,类的声明和实例化不可混淆。类的声明方式如代码清单 2-3 所示。
代码清单 2-3:类的声明方式
//命名空间类似于头文件
//using ≈ include; Systerm ≈ xxxx.h
//用户自定义命名空间,相当于新定义一个头文件
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
1.
2.
3.
4.
5.
6.
7.
8.
9.
10. //一般情况下一个上位机工程对应一个新的命名空间
11. namespace Demo
12. {
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
public partial class Form1 : Form
{
//构造函数,新建窗体工程时自动创建,可先忽略
public Form1()
{
InitializeComponent();
}
//类的声明方式
class MyClass
{
//成员声明... ...
//class 为类的关键字,MyClass 为类名
26.
27.
28.
29. }
}
}
从代码清单 2-3 可以清晰看出,类的声明非常简单。其中类的成员可以是变
量,也可以是函数方法。
2.4 Main: 程序由你开始
每一个 C#程序都必须有一个类带有 Main 函数(方法),它是程序的开始,它
通常被声明在 Program 类中。这就好比我们在开发单片机时喜欢将 main 函数声
明在 main.c 中一样。通常 Program.cs 文件随工程一起创建,详细代码见图 2-1。
图 2-1
从图中我们清晰的看到了 Class 关键字,其实 Program.cs 本身就是一个类文
件。
2.5 变量与常量
2.5.1 值类型与引用类型
值类型和我们单片机开发中的数据类型类似,需要一段独立内存存放它的实
际数据。如果值类型变量定义在方法(函数)内部那么在调用结束后这片内存回收。
相反如果定义为全局,那这片内存则不会被回收。这和 C 基本一样。char,int
float,enum,struct 等都是值类型。
引用类型是一个特殊的类型,它的存储需要两片内存。实例数据存放在堆中,
引用存放在栈中,引用可以理解为指针。具体引用类型为什么需要两片内存不再
做任何讨论,我们只需要知道引用类型的使用和常规的值类型有什么区别就行。
C 语言中如果我们表示一段字符串可以定义一个指针,在 C#中直接使用 string 关
键字即可定义。string 便是一个非常典型的引用类型,它不遵循值类型的规则。
当我们定义一个 string 类型变量并且第一次赋值时假设它在地址 0x02000000 中,
那么在第二次赋值再次查看内存时,它已经不在上一次地址中,即引用类型每次
在使用后都会变更内存地址。引用类型在并行多线程的使用中尤为重要。
当然,在上位机开发中我们可以将引用类型当作一般类型来使用。
2.5.2 声明变量
C#声明变量和 C 语言相同,声明过程完成两件事。
●给变量命名,并且关联一种类型
●编译器为其分配一片内存
2.5.3 变量的作用域
类中的变量作用域就在类中,类被回收,变量即被回收。方法(函数)内部变
量作用域为整个方法体。其中如果变量是某循环某判断中定义的,作用域就在循
环或者判断体内。
2.5.4 访问修饰符
代码清单 2-3 中类的声明在 class 前未添加任何访问修饰符,C#规定无访问修
饰符的情况下类成员即为隐式私有,外部不可访问。
C#常用的访问修饰符有以下 5 个。
◇私有的:private
◇公开的:public
◇受保护的:protected
◇内部的:internal
◇受保护内部的:protected internal
顾名思义,private 私有即外部不可访问,只能在类的内部使用,而 public
修饰的变量则可以在类的外部访问。关于 private 和 public 以及变量在类中的
使用查看代码清单 2-4。
代码清单 2-4:访问修饰符及变量在类中的简单使用
1.
2.
3.
4.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
//命名空间类似于头文件
//using ≈ include; Systerm ≈ xxxx.h