目录:
1.c#的特点
2.关于命名空间的作用
3.c#的结构代码和Java无异
4.关于c#类的创建,方法创建,修饰符号&数据类型
5.类型推断&常量定义&命名规则、
6.c#语法糖
7.c#中的预处理指令
8.C#中常见的命名空间以及modbus协议通讯的库
1.C#语言具备以下特点:
简单、安全:在C#语言中已经不再使用指针,而且不允许直接读取内存等不安全的操作。使用命名空间来管理C#文件,命名空间相当于一个文件夹,在创建程序时,允许在一个命名空间中创建一个或多个类,方便调用和重用。切记c#是区分大小写的。
面向对象:C#语言具有面向对象语言的基本特征,即封装、继承、 多态。
支持跨平台:能在多个操作系统上使用,例如Windows、Mac、Linux等。此外,还能将其应用到手机、PDA等设备上。
开发多种类型的程序:不仅能开发在控制台下运行的应用程序,也能开发 Windows 窗体应用程序、网站、手机应用等多种应用程序。
空间命名的作用:
- 合理划分:根据项目的逻辑结构和功能,合理划分命名空间。
- 避免过深的层次:命名空间的层次不宜过深,以免造成引用和理解的困难。
- 使用有意义的名称:命名空间的名称应该反映其包含的代码的功能或用途。
命名空间是C#和其他许多编程语言中的一个基本概念,它有助于提高代码的可读性和可维护性,同时确保代码的整洁和有序。
c#的结构代码和Java无异&类的定义
类包含成员,成员可以是静态或实例成员,静态成员属于类,实例成员属于对象。静态成员使用static修饰符声明。class
是定义类的关键字。
类的访问修饰符 修饰符 类名 { 类的成员 }
字段修饰符
- public:允许从任何地方访问字段。
- private:只允许在声明字段的类内部访问。
- protected:允许在声明字段的类内部或其派生类中访问。
- internal:允许在同一程序集内部访问。
- protected internal:允许在同一程序集内部或在派生类中访问。
- readonly:字段的值只能在声明时或类的构造函数中设置,之后不能更改。
- static:字段属于类本身,而不是类的实例。所有实例共享同一个静态字段。
- const:字段的值在编译时就已经确定,不能在运行时更改。
类修饰符
- public:允许从任何地方访问类。
- internal:只允许在同一程序集内部访问类。
- abstract:表示类不能被实例化,只能被用作基类。抽象类可以包含抽象方法(没有实现的方法)。
- sealed:表示类不能被继承。密封类用于防止其他类继承它。
- static:静态类不能被实例化,其成员也必须是静态的。静态类通常用于组织一组相关的功能,如工具类。
- partial:表示类的定义可以分散在多个文件中。这对于大型项目或使用代码生成工具时非常有用。
3.3 方法的定义
访问修饰符 修饰符 返回值类型 方法名(参数列表)
{
语句块;
}
访问修饰符:
所有类成员访问修饰符都可以使用,如果省略访问修饰符,默认是 private。
修饰符:
在定义方法时修饰符包括virtual(虚拟的)、abstract(抽象的)、override(重写的)、static(静态的)、sealed(密封的)。override是在类之间继承时使用的。
返回值类型:
用于在调用方法后得到返回结果,返回值可以是任意的数据类型,如果指定了返回值类型,必须使用 return 关键字返回一个与之类型匹配的值。如果没有指定返回值类型,必须使用 void 关键字表示没有返回值。
方法名:
对方法所实现功能的描述。方法名的命名是以 Pascal 命名法为规范的。
参数列表:
在方法中允许有 0 到多个参数,如果没有指定参数也要保留参数列表的小括号。参数的定义形式是数据类型 参数名,如果使用多个参数,多个参数之间需要用逗号隔开。
using System;
class Compute
{
//加法
public double Add(double num1, double num2)
{
return num1 + num2;
}
//减法
public double Minus(double num1, double num2)
{
return num1 - num2;
}
//乘法
public double Multiply(double num1, double num2)
{
return num1 * num2;
}
//除法
public double Divide(double num1, double num2)
{
return num1 / num2;
}
}
class Program
{
static void Main(string[] args)
{
Compute c = new Compute();
double ans = c.Add(1, 2);
Console.WriteLine("计算结果为:" + ans);
}
}
// 计算结果为:3
get和set访问器
属性经常与字段连用,并提供了get
访问器和set
访问器,分别用于获取或设置字段的值。字段最好把声明为private,使用属性来访问字段。
这里的get,set就和Java的不一样了,c#的需要借助一个中间值来传递复制。
在C#中,value
是一个特殊的隐式参数,它在属性或索引器的 set
访问器中自动提供。当你为一个属性设置新值时,value
关键字代表了你正在尝试设置的值。
下面是一个简单的例子来说明 value
的用法:
public class Example
{
private int myValue;
public int MyValue
{
get { return myValue; }
set
{
// value 在这里代表了尝试设置给 MyValue 属性的值
if (value >= 0)
{
myValue = value;
}
else
{
myValue = 0; // 如果值小于0,则将其设置为0
}
}
}
}
在这个例子中,当你尝试设置 MyValue
属性的值时,value
关键字代表了你传递给 set
访问器的值。例如:
Example example = new Example();
example.MyValue = -5; // 这里 -5 就是 value
在 set
访问器内部,你可以使用 value
来检查、修改或验证这个值,然后再将其赋给私有字段 myValue
。如果 value
小于0,set
访问器会将 myValue
设置为0,否则它会直接将 value
赋给 myValue
。
这种机制允许你在设置属性的值时执行额外的逻辑,而不需要在调用代码中显式传递参数。这是C#中属性的一种强大功能,它提供了对字段访问的控制和灵活性。
using System;
允许引用Console类的静态成员而忽略名称空间和类名;namespace test
声明名称空间,名称空间是把相关的类组合在一起的方式;- 所有的C#代码都必须包含在类中;
- 每个C#可执行文件都必须有一个入口点Main()方法。
关于c#的数据类型
有符号数(Signed)
有符号数可以表示正数、负数和零。在有符号数中,通常使用一个二进制位(通常是最左边的位)来表示数的正负。例如,在8位的 byte
类型中,一个位用于表示符号,剩下的7位用于表示数值,因此可以表示的范围是 -128 到 127。
无符号数(Unsigned)
无符号数只能表示正数和零,不能表示负数。因为没有用于表示符号的位,所有的位都用于表示数值,因此无符号数可以表示更大的正数值。例如,在8位的 byte
类型中,如果作为无符号数,它可以表示的范围是 0 到 255。
无符号数的应用
无符号数在某些场景下非常有用,例如:
- 内存地址:在处理内存地址时,通常使用无符号数,因为地址总是非负的。
- 计数器:在需要计数的情况下,无符号数可以提供更大的正数值范围。
- 位操作:在进行位操作时,无符号数可以避免由于符号位引起的潜在问题。
在C#中使用无符号数
在C#中,byte
类型默认是无符号的,而 short
、int
和 long
默认是有符号的。C#也提供了无符号版本的这些类型,如 ushort
、uint
和 ulong
。
// 无符号整型示例 uint positiveNumber = 42; // 无符号整数,范围是 0 到 4,294,967,295 ulong veryLargeNumber = 1234567890123456789; // 无符号长整数,范围是 0 到 18,446,744,073,709,551,615
注意事项
- 溢出:无符号数在尝试存储超出其范围的负数时,会发生溢出,这可能导致不可预测的行为。
- 兼容性:在与其他语言或系统交互时,需要注意数据类型的兼容性,因为不是所有的语言都支持无符号数。
无符号数在需要处理非负数值的场景中非常有用,但在使用时需要小心处理可能的溢出情况。
2.4 类型推断
类型推断使用关键字var,使用var关键字代替实际类型,编译器可以根据变量的初始化值“推断”变量的类型。
// 两者相等
var someNumber = 0;
int someNumber = 0;
1
2
3
类型推断遵循的规则:
变量必须初始化;
初始化器不能为空;
初始化器必须放在表达式中;
不能把初始化器设置为一个对象,除非在初始化器中创建了一个新对象。
2.5 常量
与变量不同的是,常量在第一次被赋值后值就不能再改变。定义常量需要使用关键字const来完成。常量的值必须能在编译时用于计算,不能用从变量中提取的值来初始化常量(除非使用只读字段)。
const 数据类型 常量名 = 值;
1
使用常量的好处:
由于使用易于读取的名称代替了较难读取的数字和字符串,常量使程序变得更易于阅读;
常量使程序易于修改;
常量更容易避免程序出现错误。
在引用常量时,编译器是将常量的值替换常量,故常量必须在声明时初始化。
2.6 命名规则
标识符命名必须以字母或下划线开头; 不能把C#关键字用作标识符。 常用的命名方法有两种,一种是Pascal命名法(帕斯卡命名法),另一种是Camel命名法(驼峰命名法)。 Pascal命名法是指每个单词的首字母大写;Camel命名法是指第一个单词小写,从第二个单词开始每个单词的首字母大写。
2.7 c#语法糖
在C#中,foreach
循环用于遍历集合中的元素,如数组、列表或其他任何实现了 IEnumerable
接口的对象。以下是一个简单的示例,展示了如何使用 foreach
循环来遍历一个整数数组,并打印每个元素的值:
using System;
class Program
{
static void Main()
{
// 定义一个整数数组
int[] numbers = { 1, 2, 3, 4, 5 };
// 使用 foreach 循环遍历数组
foreach (int number in numbers)
{
// 打印每个元素的值
Console.WriteLine(number);
}
}
}
在这个示例中,foreach
循环会自动遍历数组 numbers
中的每个元素。
2.8 c#中的预处理指令
在C#中,预处理指令提供了一种在实际编译开始之前对代码进行预处理的方法。这些指令通常以 #
开头,用于控制编译过程,例如定义常量、条件编译、生成错误或警告等。提到的预处理指令的详细解释:
//在C#中,#define 预处理指令用于定义一个符号,这个符号可以在条件编译中使用。
//这通常用于在编译时根据是否定义了某个符号来决定包含或排除特定的代码块。
//以下是一个具体的例子:
#define DEBUG
using System;
class Program
{
static void Main()
{
#if DEBUG
Console.WriteLine("Debug mode is enabled.");
#else
Console.WriteLine("Debug mode is disabled.");
#endif
}
}
//在这个例子中,#define DEBUG 定义了一个名为 DEBUG 的符号。
//在 Main 方法中,我们使用 #if DEBUG 来检查这个符号是否被定义。如果 DEBUG 被定义了
//(即我们在代码中使用了 #define DEBUG),那么 Console.WriteLine("Debug mode is enabled.");
//这行代码将被编译并执行。如果 DEBUG 没有被定义,
//那么 Console.WriteLine("Debug mode is disabled."); 这行代码将被编译并执行。
-
#define
- 描述: 定义一个符号。一旦定义,该符号可以在条件编译中使用。
- 用途: 通常用于定义编译时常量,例如
#define DEBUG
,然后可以在代码中使用#if DEBUG
来包含或排除特定于调试的代码。
-
#undef
- 描述: 取消已定义的符号。
- 用途: 用于移除之前用
#define
定义的符号,使得该符号在后续的条件编译中不再被识别。
-
#if
- 描述: 测试一个符号是否已定义。
- 用途: 用于条件编译,可以根据是否定义了某个符号来决定编译哪些代码。
-
#else
- 描述: 与
#if
一起使用,提供另一个条件编译选项。 - 用途: 当
#if
的条件不满足时,编译#else
后面的代码。
- 描述: 与
-
#elif
- 描述: 复合条件指令,相当于
#else if
。 - 用途: 提供多个条件编译选项,如果前面的
#if
和#elif
条件都不满足,可以继续测试下一个#elif
条件。
- 描述: 复合条件指令,相当于
-
#endif
- 描述: 指定条件指令的结束。
- 用途: 每个
#if
、#elif
、#else
指令都必须以#endif
结束。
-
#line
- 描述: 修改编译器的行号和文件名输出。
- 用途: 用于控制错误和警告消息中显示的行号和文件名,常用于调试或与自动生成的代码一起使用。
-
#error
- 描述: 从代码中生成一个编译错误。
- 用途: 用于确保某些条件不被满足时,编译过程会停止并显示错误信息。
-
#warning
- 描述: 从代码中生成一个编译警告。
- 用途: 用于提醒开发者注意某些代码条件,但不会阻止编译过程。
-
#region 和 #endregion
- 描述:
#region
允许指定一个可展开或折叠的代码块,#endregion
标记该块的结束。 - 用途: 在 Visual Studio 等IDE中,这些指令用于组织代码,使得代码结构更清晰,便于浏览和编辑。
- 描述:
这些预处理指令在编译时处理,不参与程序的运行时执行。它们主要用于代码的组织、调试和控制编译流程。
2.9C#中的命名空间,直接理解为库,以下科普一下常见的命名空间,以及这些命名空间(就是库啦)里常用的方法
在.NET框架中,有许多预定义的库(命名空间),它们提供了广泛的功能,从基本的类型操作到复杂的网络通信和数据处理。以下是一些常见的.NET库及其常用方法的概述:
1. System
这是最基本的命名空间,包含了最常用的类型,如数据类型、数学运算、异常处理等。
- Math 类:提供数学函数,如
Math.Sqrt(double)
、Math.Sin(double)
、Math.Max(int, int)
等。 - Convert 类:用于类型转换,如
Convert.ToInt32(string)
、Convert.ToString(int)
等。 - String 类:提供字符串操作,如
String.Format(string, object)
、String.IsNullOrEmpty(string)
等。
2. System.Collections
包含用于处理集合的类,如列表、字典、队列等。
- List<T> 类:提供列表操作,如
List<int>.Add(int)
、List<int>.RemoveAt(int)
等。 - Dictionary<TKey, TValue> 类:提供键值对存储,如
Dictionary<string, int>.Add(string, int)
、Dictionary<string, int>.ContainsKey(string)
等。
3. System.IO
用于文件和数据流的输入输出操作。
- File 类:提供文件操作,如
File.ReadAllText(string)
、File.WriteAllText(string, string)
等。 - StreamReader 和 StreamWriter 类:用于读写文本数据流。
4. System.Net
用于网络编程,包括HTTP、FTP等协议的支持。
- HttpClient 类:用于发送HTTP请求,如
HttpClient.GetAsync(string)
、HttpClient.PostAsync(string, HttpContent)
等。 - WebClient 类:提供简单的网络功能,如
WebClient.DownloadFile(string, string)
、WebClient.UploadFile(string, string)
等。
5. System.Data
用于数据库操作,包括ADO.NET的核心类。
- SqlConnection 类:用于连接SQL Server数据库。
- SqlCommand 类:用于执行SQL命令。
- DataSet 和 DataTable 类:用于存储和操作从数据库检索的数据。
6. System.Linq
提供LINQ(语言集成查询)功能,用于查询集合和数据源。
- Enumerable 类:提供LINQ查询操作,如
Enumerable.Where(IEnumerable<T>, Func<T, bool>)
、Enumerable.OrderBy(IEnumerable<T>, Func<T, TKey>)
等。
7. System.Threading
用于多线程编程。
- Thread 类:用于创建和管理线程。
- Mutex 和 Semaphore 类:用于同步线程。
8. System.Reflection
用于在运行时检查和操作程序集、类型、对象等。
- Assembly 类:用于加载和检查程序集。
- Type 类:用于获取类型信息。
Modbus 是一种通信协议,广泛用于工业自动化系统中,特别是在PLC(可编程逻辑控制器)和RTU(远程终端单元)之间的通信。Modbus 协议支持多种物理层,包括串行通信(如RS-232和RS-485)和以太网(Modbus TCP)。
在.NET环境中,有几个库可以用来实现Modbus通信,其中最常用的是 Modbus.NET
。这个库提供了一个简单易用的API,用于在C#应用程序中实现Modbus通信。
主要特点
- 支持多种Modbus模式:包括Modbus RTU、Modbus ASCII和Modbus TCP。
- 易于集成:库提供了清晰的API,可以轻松集成到现有的.NET项目中。
- 灵活性:可以配置不同的串行端口参数和网络设置。
- 错误处理:提供了错误处理机制,帮助开发者处理通信过程中的异常。
使用示例
以下是一个使用 Modbus.NET
库通过Modbus TCP协议读取PLC数据的简单示例:
using System;
using Modbus.Data;
using Modbus.Device;
using Modbus.Utility;
class Program
{
static void Main()
{
// 创建Modbus TCP Master实例
using (TcpMaster master = new TcpMaster(new ModbusIpMaster(new Modbus()), "192.168.1.3"))
{
try
{
// 连接到PLC
master.Connect();
if (master.IsConnected)
{
Console.WriteLine("Connected to PLC");
// 读取寄存器数据
ushort startAddress = 0;
ushort numOfPoints = 10;
ushort[] registers = master.ReadHoldingRegisters(startAddress, numOfPoints);
if (registers != null)
{
Console.WriteLine("Data from PLC:");
foreach (ushort register in registers)
{
Console.WriteLine(register);
}
}
else
{
Console.WriteLine("Failed to read data");
}
}
else
{
Console.WriteLine("Failed to connect to PLC");
}
// 断开连接
master.Disconnect();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
在这个例子中,我们使用 Modbus.NET
库创建了一个Modbus TCP主站实例,连接到PLC,并读取了保持寄存器的数据。
注意事项
- 确保你的PLC支持Modbus协议,并且已经正确配置。
- 根据你的PLC的实际IP地址和寄存器配置调整代码中的参数。
- 在实际应用中,可能需要处理更复杂的逻辑,例如错误处理、数据写入等。
Modbus.NET
是一个功能强大且易于使用的库,非常适合在.NET环境中实现Modbus通信。