C#开发学习杂笔(更新中)
- using相当于C中的include
- C#中大小写敏感;
- 最后一行写 Console.ReadKey(); 是针对 VS.NET 用户的。这使得程序会等待一个按键的动作,防止程序从 Visual Studio .NET 启动时屏幕会快速运行并关闭。
- 与 Java 不同的是,文件名可以不同于类的名称。
- namespace 相当于统一的一个包,里面包含了一系列的类class。
- 隐式转换
byte b = 5;
int i = b;
int intValue = 42;
long longValue = intValue;
将一个较小范围的数据类型转换为较大范围的数据类型时,编译器会自动完成类型转换,这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。
- 显式转换
指将一个较大范围的数据类型转换为较小范围的数据类型时,或者将一个对象类型转换为另一个对象类型时,需要使用强制类型转换符号进行显示转换,强制转换会造成数据丢失。
例如,将一个 int 类型的变量赋值给 byte 类型的变量,需要显示转换。
int i = 10;
byte b = (byte)i; // 显式转换,需要使用强制类型转换符号
或者
double doubleValue = 3.14;
int intValue = (int)doubleValue; // 强制从 double 到 int,数据可能损失小数部分
int intValue = 42;
float floatValue = (float)intValue; // 强制从 int 到 float,数据可能损失精度
int intValue = 123;
string stringValue = intValue.ToString(); // 将 int 转换为字符串
- C# 内置的类型转换方法:
序号 | 方法 & 描述 |
---|---|
1 | ToBoolean 如果可能的话,把类型转换为布尔型。 |
2 | ToByte 把类型转换为字节类型。 |
3 | ToChar 如果可能的话,把类型转换为单个 Unicode 字符类型。 |
4 | ToDateTime 把类型(整数或字符串类型)转换为 日期-时间 结构。 |
5 | ToDecimal 把浮点型或整数类型转换为十进制类型。 |
6 | ToDouble 把类型转换为双精度浮点型。 |
7 | ToInt16 把类型转换为 16 位整数类型。 |
8 | ToInt32 把类型转换为 32 位整数类型。 |
9 | ToInt64 把类型转换为 64 位整数类型。 |
10 | ToSbyte 把类型转换为有符号字节类型。 |
11 | ToSingle 把类型转换为小浮点数类型。 |
12 | ToString 把类型转换为字符串类型。 |
13 | ToType 把类型转换为指定类型。 |
14 | ToUInt16 把类型转换为 16 位无符号整数类型。 |
15 | ToUInt32 把类型转换为 32 位无符号整数类型。 |
16 | ToUInt64 把类型转换为 64 位无符号整数类型。 |
这些方法都定义在 System.Convert 类中,使用时需要包含 System 命名空间。它们提供了一种安全的方式来执行类型转换,因为它们可以处理 null值,并且会抛出异常,如果转换不可能进行。
注意点:
- 隐式转换只能将较小范围的数据类型转换为较大范围的数据类型,不能将较大范围的数据类型转换为较小范围的数据类型;
- 显式转换可能会导致数据丢失或精度降低,需要进行数据类型的兼容性检查;
- 对于对象类型的转换,需要进行类型转换的兼容性检查和类型转换的安全性检查。
Parse 方法用于将字符串转换为对应的数值类型,如果转换失败会抛出异常。
string str = "123.45";
double d = double.Parse(str);
- C# 内置类型转换方法的表格:
方法类别 | 方法 | 描述 |
---|---|---|
隐式转换 | 自动进行的转换 | 无需显式指定,通常用于安全的类型转换,如从较小类型到较大类型 |
显式转换(强制转换) | (type)value | 需要显式指定,通常用于可能导致数据丢失或转换失败的情况 |
Convert 类方法 | Convert.ToBoolean(value) | 将指定类型转换为 Boolean |
Convert.ToByte(value) | 将指定类型转换为 Byte | |
Convert.ToChar(value) | 将指定类型转换为 Char | |
Convert.ToDateTime(value) | 将指定类型转换为 DateTime | |
Convert.ToDecimal(value) | 将指定类型转换为 Decimal | |
Convert.ToDouble(value) | 将指定类型转换为 Double | |
Convert.ToInt16(value) | 将指定类型转换为 Int16 (短整型) | |
Convert.ToInt32(value) | 将指定类型转换为 Int32 (整型) | |
Convert.ToInt64(value) | 将指定类型转换为 Int64 (长整型) | |
Convert.ToSByte(value) | 将指定类型转换为 SByte | |
Convert.ToSingle(value) | 将指定类型转换为 Single (单精度浮点型) | |
Convert.ToString(value) | 将指定类型转换为 String | |
Convert.ToUInt16(value) | 将指定类型转换为 UInt16 (无符号短整型) | |
Convert.ToUInt32(value) | 将指定类型转换为 UInt32 (无符号整型) | |
Convert.ToUInt64(value) | 将指定类型转换为 UInt64 (无符号长整型) | |
Parse 方法 | Boolean.Parse(string) | 将字符串解析为 Boolean |
Byte.Parse(string) | 将字符串解析为 Byte | |
Char.Parse(string) | 将字符串解析为 Char | |
DateTime.Parse(string) | 将字符串解析为 DateTime | |
Decimal.Parse(string) | 将字符串解析为 Decimal | |
Double.Parse(string) | 将字符串解析为 Double | |
Int16.Parse(string) | 将字符串解析为 Int16 | |
Int32.Parse(string) | 将字符串解析为 Int32 | |
Int64.Parse(string) | 将字符串解析为 Int64 | |
SByte.Parse(string) | 将字符串解析为 SByte | |
Single.Parse(string) | 将字符串解析为 Single | |
UInt16.Parse(string) | 将字符串解析为 UInt16 | |
UInt32.Parse(string) | 将字符串解析为 UInt32 | |
UInt64.Parse(string) | 将字符串解析为 UInt64 | |
TryParse 方法 | Boolean.TryParse(string, out bool) | 尝试将字符串解析为 Boolean ,返回布尔值表示是否成功 |
Byte.TryParse(string, out byte) | 尝试将字符串解析为 Byte ,返回布尔值表示是否成功 | |
Char.TryParse(string, out char) | 尝试将字符串解析为 Char ,返回布尔值表示是否成功 | |
DateTime.TryParse(string, out DateTime) | 尝试将字符串解析为 DateTime ,返回布尔值表示是否成功 | |
Decimal.TryParse(string, out decimal) | 尝试将字符串解析为 Decimal ,返回布尔值表示是否成功 | |
Double.TryParse(string, out double) | 尝试将字符串解析为 Double ,返回布尔值表示是否成功 | |
Int16.TryParse(string, out short) | 尝试将字符串解析为 Int16 ,返回布尔值表示是否成功 | |
Int32.TryParse(string, out int) | 尝试将字符串解析为 Int32 ,返回布尔值表示是否成功 | |
Int64.TryParse(string, out long) | 尝试将字符串解析为 Int64 ,返回布尔值表示是否成功 | |
SByte.TryParse(string, out sbyte) | 尝试将字符串解析为 SByte ,返回布尔值表示是否成功 | |
Single.TryParse(string, out float) | 尝试将字符串解析为 Single ,返回布尔值表示是否成功 | |
UInt16.TryParse(string, out ushort) | 尝试将字符串解析为 UInt16 ,返回布尔值表示是否成功 | |
UInt32.TryParse(string, out uint) | 尝试将字符串解析为 UInt32 ,返回布尔值表示是否成功 | |
UInt64.TryParse(string, out ulong) | 尝试将字符串解析为 UInt64 ,返回布尔值表示是否成功 |
- System 命名空间中的 Console 类提供了一个函数 ReadLine(),用于接收来自用户的输入,并把它存储到一个变量中。
int num;
num = Convert.ToInt32(Console.ReadLine());
示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Module1
{internal class Demo4{public static void Main(string[] args){int num;Console.WriteLine("请输入一个整数:");num = Convert.ToInt32(Console.ReadLine());Console.WriteLine("获取到的数为:" + num);}}
}
- C# 转义序列码:
转义序列 | 含义 |
---|---|
\\ | \ 字符 |
\' | ' 字符 |
\" | " 字符 |
\? | ? 字符 |
\a | Alert 或 bell |
\b | 退格键(Backspace) |
\f | 换页符(Form feed) |
\n | 换行符(Newline) |
\r | 回车 |
\t | 水平制表符 tab |
\v | 垂直制表符 tab |
\ooo | 一到三位的八进制数 |
\xhh . . . | 一个或多个数字的十六进制数 |
字符常量是括在单引号里,例如,'x'
字符串常量是括在双引号 "" 里,或者是括在 @"" 里。
C# 支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
---|---|---|
& | 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。 | (A & B) 将得到 12,即为 0000 1100 |
| | 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。 | (A | B) 将得到 61,即为 0011 1101 |
^ | 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。 | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 按位取反运算符是一元运算符,具有"翻转"位效果,即0变成1,1变成0,包括符号位。 | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 | A >> 2 将得到 15,即为 0000 1111 |
- C# 支持的赋值运算符:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
C# 支持的其他一些重要的运算符,包括 sizeof、typeof 和 ? :。
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回数据类型的大小。 | sizeof(int),将返回 4. |
typeof() | 返回 class 的类型。 | typeof(StreamReader); |
& | 返回变量的地址。 | &a; 将得到变量的实际地址。 |
* | 变量的指针。 | *a; 将指向一个变量。 |
? : | 条件表达式 | 如果条件为真 ? 则为 X : 否则为 Y |
is | 判断对象是否为某一类型。 | If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 |
as | 强制转换,即使转换失败也不会抛出异常。 | Object obj = new StringReader("Hello"); StringReader r = obj as StringReader; |
typeof 关键字用于获取一个类型的类型对象,它通常用于反射和动态创建类型实例。
下面是一个使用 typeof 的简单示例:
using System;
class Program
{
static void Main(string[] args)
{
Type type = typeof(string);
Console.WriteLine(type.FullName);
Console.ReadKey();
}
}
在上面的代码中,我们使用 typeof 关键字来获取 string 类型的类型对象,并将其存储在 Type 类型的变量 type 中,然后,我们使用 FullName 属性打印该类型的完全限定名。
当上面的代码被编译和执行时,它会产生下列结果:
System.String
- foreach
C# 也支持 foreach 循环,使用 foreach 可以迭代数组或者一个集合对象。
简单点说就是可以用foreach 循环来遍历一个数组,例如下面的示例:
using System;
using System.Collections.Generic;class Program
{static void Main(string[] args){//创建一个字符串列表List<string> myString = new List<string>();myString.Add("Google");myString.Add("Runoob");myString.Add("Taobao");int count = 0;foreach(string element in myString){count++;Console.WriteLine("Element #{0}:{1}", count, element);}}
}
输出:
Element #1:Google
Element #2:Runoob
Element #3:Taobao
当条件表达式不存在时,它被假设为真。但是一般情况下,程序员偏向于使用 for( ; ; ) 结构来表示一个无限循环。
C# 支持的访问修饰符如下所示:
- public:所有对象都可以访问;
- private:对象本身在对象内部可以访问;
- protected:只有该类对象及其子类对象可以访问
- internal:同一个程序集的对象可以访问;
- protected internal:访问限于当前程序集或派生自包含类的类型。
C#当中,如果没有指定访问修饰符,则使用类成员的默认访问修饰符,即为 private。如下代码中成员函数 GetArea() 声明的时候不带有任何访问修饰符,这个时候则默认当作采用private来修饰了。
using System;namespace RectangleApplication
{class Rectangle{//成员变量internal double length;internal double width;double GetArea(){return length * width;}public void Display(){Console.WriteLine("Length: {0}", length);Console.WriteLine("Width: {0}", width);Console.WriteLine("Area: {0}", GetArea());}}class ExecuteRectangle{static void Main(string[] args){Rectangle rect = new Rectangle();rect.length = 30.01;rect.width = 999.66;rect.Display();Console.ReadKey();}}}
数组是一个引用类型,所以需要使用 new 关键字来创建数组的实例。
double[] balance = new double[10];
数组是一种用于存储固定大小、同一类型元素的集合。理解 Array 类的特性和方法对于高效编写 C# 程序非常重要:
下表列出了 Array 类中一些最常用的属性:
属性名 | 说明 | 示例代码 | 输出 |
---|---|---|---|
Length | 获取数组中元素的总个数。 | int[] arr = {1, 2, 3}; int length = arr.Length; | 3 |
Rank | 获取数组的维数(即数组的维度)。 | int[,] matrix = new int[2, 3]; int rank = matrix.Rank; | 2 |
IsFixedSize | 判断数组的大小是否固定。 | int[] arr = {1, 2, 3}; bool fixedSize = arr.IsFixedSize; | true |
IsReadOnly | 判断数组是否为只读。 | int[] arr = {1, 2, 3}; bool readOnly = arr.IsReadOnly; | false |
IsSynchronized | 判断数组是否线程安全。 | int[] arr = {1, 2, 3}; bool sync = arr.IsSynchronized; | false |
SyncRoot | 获取用于同步数组访问的对象,通常用于多线程操作。 | int[] arr = {1, 2, 3}; object syncRoot = arr.SyncRoot; | syncRoot |
C# Array 类 | 菜鸟教程
- C# 中的构造函数
类的 构造函数 是类的一个特殊的成员函数,当创建类的新对象时执行。
构造函数的名称与类的名称完全相同,它没有任何返回类型。
默认的构造函数没有任何参数。如果需要的话,一个带有参数的构造函数可以有参数,这种构造函数叫做参数化构造函数。这可以在创建对象的同时给对象赋初始值。
类的 析构函数 是类的一个特殊的成员函数,当类的对象超出范围时执行。
析构函数的名称是在类的名称前加上一个波浪形(~)作为前缀,它不返回值,也不带任何参数。
析构函数用于在结束程序(比如关闭文件、释放内存等)之前释放资源。析构函数不能继承或重载。
一般的来说,在代码里面的析构函数都不会被执行。你甚至看不到执行结果
- 答疑点:
1、C#中使用了虚方法的继承和常规的继承有什么区别?
简单点说,就是虚方法允许派生类重写基类中的方法。通过在基类中使用 virtual
关键字声明方法,派生类可以使用 override
关键字来重写该方法。这种方式提供了更大的灵活性,因为派生类可以根据需要改变方法的行为。
反之,如果基类中的方法没有使用 virtual
关键字,派生类不能重写该方法。派生类只能隐藏(通过 new
关键字)基类的方法,但这并不会改变基类方法的行为。
2、
namespace OperatorOvlApplication44
{class Box{private double length;private double breath;private double height;public double getVolume(){return length * breath * height;}public void setLength(double len){length = len;}public void setBreath(double bre){breath = bre;}public void setHeight(double hei){height = hei;}//重载+public static Box operator+ (Box b, Box c){Box box = new Box();box.length = b.length + c.length;box.breath = b.breath + c.breath;box.height = b.height + c.height;return box;}//重载==public static bool operator == (Box lhs, Box rhs){bool status = false;if(lhs.length == rhs.length && lhs.breath == rhs.breath&& lhs.height == rhs.height){status = true;}return status;}}
}
在上述的重载==,IDE为什么一直报红?
C# 要求如果你重载了 ==
运算符,也必须重载 !=
运算符。这是因为 ==
和 !=
是逻辑上的对立操作,编译器会检查你是否同时重载了这两个运算符