|
1. C# 初识
因为先前已经学过 C++ 了,所以在C# 的学习中,大多只记录和 C++ 不同的点,在学习的过程中,感谢刘铁猛老师的教程,您是我C# 入门的领路人。
1.1 使用 .net cli
1.1.1 使用 VSCode 创建 C# 工程
先安装 C# 相关插件
创建新工程- dotnet new console -n ProjectName
复制代码 构建运行更多信息访问:https://learn.microsoft.com/en-us/dotnet/core/tutorials/with-visual-studio-code?pivots=dotnet-8-0
1.1.2 使用 Visual Studio 创建工程
按照步骤操作,不需要使用命令行,但是注意,在这里想要添加我们使用的模块,要在工程窗口的 Reference 处右键选择添加,如我要创建一个窗口应用,就需要添加 System.Windows.Form:
1.2 类的本质
类是对显式世界事物进行抽象所得的结果
- 事物包括“物质”(实体)与“运动”(逻辑)
- 建模是一个去伪存真,由表及里的过程
对象也叫实例,可以由类创建,是类经过“实例化”得到的内存中的实体。在这里我们创建一个窗口的实例,取名为 My From:- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- namespace ClassAndInstance
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // (new Form()).ShowDialog();
- Form myForm = new Form(){ Text = "My Form"};
- myForm.ShowDialog();
- Form myForm2 = myForm;
- myForm2.Text = "I changed it";
- myForm2.ShowDialog();
- }
- }
- }
复制代码 第 16 行的语句可以拆为两个部分,其中,myForm 是一个引用变量:- Form myForm = new Form();
- myForm.Text = "My Form";
复制代码 在上面的 myForm 和 myForm2 是两个对象实例,不
在 C# 中,被 internal 修饰的类,只能在同一个程序集文件中才能被访问,而在外部是访问不到的。
构建运行:
1.2.1 类的三大成员
- 属性(Property):存储数据/组合起来表示类或对象当前的状态
- 方法(Method)
- 由 C 语言中的函数( function )进化而来,表示类或对象“能做什么”
- 工作中 90% 的时间是在与方法打交道,因为它是真正做事“构成逻辑”的成员
- 事件(Event)
- 类或对象通知其它类或对象的机制,为 C# 所特有( Java 通过其它办法实现这个机制,而在C++中要使用事件机制,则要使用 Qt 或者 libevent 库)
- 善用事件机制非常重要(但是不能滥用)
使用 MSDN 本地文档
将光标移动到想要查询的类上面,然后按 F1。不过新版的 VS 默认使用在线文档,但也可以手动替换为使用本地文档,步骤如下:
- Visual Studio 自带了 Help Viewer
- 点击 Visual Studio Help --> Set Help Preference --> Launch in Help Viewer --> 若提示下载,就点击下载
文档中的 Remarks 很有帮助,线程安全性也可以在 msdn 上面查询
本地文档界面:
以属性侧重的类
如 EntityFramework
- 先使用 NuGet 安装 EntityFramework:
在工程模块的 Dependencies(Referencies) 右键,然后选择 Manage NuGet Packages,然后搜索 EntityFramework(注意,如果是使用的 .net 框架,而不是 .net framework,要选择的是 EntityFramworkCore ,这两者是不一样的),然后点击安装。
- 然后下载示例数据库文件:AdventureWorksLT2012.bak ,具体的安装步骤参见链接,在这里我使用了 SQL Server Management Studio 19
- 选择我们需要的数据表:SalesLT.Product,查询它的前 1000 行:
- SELECT TOP (1000) [ProductID]
- ,[Name]
- ,[ProductNumber]
- ,[Color]
- ,[StandardCost]
- ,[ListPrice]
- ,[Size]
- ,[Weight]
- ,[ProductCategoryID]
- ,[ProductModelID]
- ,[SellStartDate]
- ,[SellEndDate]
- ,[DiscontinuedDate]
- ,[ThumbNailPhoto]
- ,[ThumbnailPhotoFileName]
- ,[rowguid]
- ,[ModifiedDate]
- FROM [AdventureWorksLT2012].[SalesLT].[Product]
复制代码
确实是可以查询到的
- 在Visual Studio 新建一个 Item,类型为:ADO.NET Entity Data Model,连接到上面的 AdventureWorksLT2012
当前工程名 -> 右键 -> Add -> New Item... 然后选择如下类型,名称为 AdventureWorksModel:
选择生成的方式:EF Designer from database(老版本的直接选择数据库生成),然后点击下一步
这里的主机名称等信息就填写自己的数据库那里的信息,如我的名称如下所示,然后再选择想要连接的数据库名(这里为 AdventureWorksLT2012)
- 选择需要的数据表,我这里选择了 SalesLT 中的 Product 和 Address,注意这里生成的 Model Namespace
然后再我们的VS工程目录下就生成了数据传输使用的数据模式类:
这个类里面都是属性(Property),没有方法和事件,生成的这两个diagram中的小扳手图标表示的就是属性,这里的每一个属性,都是数据表中的一个字段:
编写代码:- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace PropertySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- AdventureWorksLT2012Entities proxy = new AdventureWorksLT2012Entities();
- foreach (Product p in proxy.Product)
- {
- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(p.Name); // 打印 Product 中的名字
- }
- Console.WriteLine(proxy.Product.Count()); // 打印 Product 中的行数
- }
- }
- }
复制代码 编译运行结果:
以方法侧重的类
如 Math, Console
示例:- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace MethodSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- double x = Math.Sqrt(2);
- Console.WriteLine(x);
- double y = Math.Pow(x, 3);
- Console.WriteLine($"{y:f6}"); // 2.828427
- }
- }
- }
复制代码 编译运行结果:
以事件侧重的类
如各种 Timer
我们新建一个 WPF 示例程序,在里面拖入一个文本框(textBox),名称取为 timeTextBox,它会显式本地时间,文本设置为居中,将 FontSize 设置为 36px,将原本的 Text 清理掉:
然后编译运行,就编写了一个简单的本地计时器:
代码:
MainWindow.xmal.cs- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using System.Windows.Threading; // DispatcherTimer 类所在名称空间
- namespace EventSample
- {
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent(); // 主窗口的构造函数
- DispatcherTimer timer = new DispatcherTimer(); // 创建一个计时器
- timer.Interval = TimeSpan.FromSeconds(1); // 计时间隔
- timer.Tick += timer_Tick; // 当Tick事件发生时,执行函数 timer_Tick
- timer.Start();
- }
- private void timer_Tick(object sender, EventArgs e)
- {
- this.timeTextBox.Text = DateTime.Now.ToString(); // 获取窗口的文本框内容,该内容为当前的时间,格式转为string
- }
- }
- }
复制代码 在上面的代码中,写到第 29 行的 += 处,可以按两下 TAB 键来生成事件处理器相关代码(包括下面的 timer_Tick 函数,不过里面的具体实现需要我们自己按照自己需求来写,这里是让 timeTextBox 文本框中的 Text 显示为本地时间)。
MainWindow.xaml- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>
复制代码 1.2.2 静态成员和实例成员
- 静态(Static)成员在语义上表示它是“类的成员”
- 实例(非静态)成员在语义上表示它是“对象的成员”
- 绑定(Binding)指的是编译期如何把一个成员与类或对象关联起来:. 操作符实现成员访问
- 绑定分为早绑定和晚绑定,早绑定时在编译期间进行绑定,而晚绑定则是运行期间再进行绑定
2. 基础详解
2.1 构成 C# 语言的基本元素
2.1.1 标记(Token)
关键字(Keyword)、操作符(Operator)、标识符(Identifier)、标点符号、文本(字面值,Literal)都可以算作 Token
注释与空白不算做 Token
关键字
关键字是预定义的保留标识符,对编译器有特殊意义。 除非前面有 @ 前缀,否则不能在程序中用作标识符。 例如,@if 是有效标识符,而 if 则不是,因为 if 是关键字。C# 的关键字分为常见关键字和上下文关键字,可以见此网站
操作符
C# 中特殊的操作符为:?? 和 ?,除此之外与C++大致相同
- ?:指可为 null 的类型,将 null 赋值给数值类型或布尔型以及日期类型的功能
- ??:称为 null 合并运算符,用于定义可为 null 值的类型和引用类型的默认值
示例代码:- class MyProgram
- {
- static void Main(string[] args) {
- int? x = null;
- // int y = null; // Error
-
- int z = x ?? 2000; // x 不为null,则返回左操作数,x为null则返回右操作数2000
- Console.WriteLine(z);
- }
- }
复制代码 编译运行结果:标识符
必须以字符(英文字母或者其他语言字符)或者下划线开头,我们要求标识符是有意义的。方法一般为动词(建议使用 lowerCamelCase ),类和名称空间为名词(建议采用 UpperCamelCase/PascalCase ),匈牙利命名法一般在 C# 中不常用
字面值
下面是常见的字面值:注意:在 C# 中,string 类型的传递为引用传递,但是看起来像是值传递。如上面代码的第 10 行:将 str 拷贝给 str1,实际上编译器先构造了一个临时的 string 类型实例,然后将这个新构造的实例引用传递给了 str1。
编译运行结果:
简单程序示例:- namespace MyCalculator
- {
- class Calculator
- {
- public double Add(double x, double y)
- {
- return x + y;
- }
- public double Mul(double x, double y)
- {
- return x * y;
- }
- public double Sub(double x, double y)
- {
- return x - y;
- }
- public double Div(double x, double y)
- {
- return (x / y) * y;
- }
- }
- internal class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Hello, World!");
- double x1 = 3.1;
- double x2 = 0;
- Calculator cal1 = new Calculator();
- double res = cal1.Mul(x1, x2);
- double res1 = cal1.Div(x1, x2);
- Console.WriteLine(res1);
- }
- }
- }
复制代码 简单的算法题:汉诺塔
解法:将 n - 1 个碟看为一个,然后总步骤就为三个:
- 第 n - 1 个碟从起始柱 --> 辅助柱子
- 第 n 个碟从起始柱 --> 目的柱
- 第 n - 1 个从辅助柱 --> 目的柱
- namespace TowerOfHanoi{ internal class Program { static void Main(string[] args) { Hanoi h = new Hanoi(); uint n = 3; char start = 'A'; char dest = 'C'; char temp = 'B'; h.Move(n, start, dest, temp); } } class Hanoi { static int counter = 0; public void Move(uint count, char from, char to, char buffer) { if (count == 1) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine($" {from} --> {to}");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>counter++; } else {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Move(count - 1, from, buffer, to); // 移动第 n - 1 个盘子,从起始柱 --> 辅助柱<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine($" {from} --> {to}"); // 移动第 n 个盘子,从起始柱 --> 目的柱<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Move(count - 1, buffer, to, from); // 移动第 n - 1 个盘子,从辅助柱 --> 目的柱 } } }}
复制代码 编译运行结果:
2.2 类型
2.2.1 布尔类型转换
C# 是典型的强类型语言。
在这里需要明确的是,C# 的类型是规定了具体长度的,如 int 为 32 bite(4 byte) ,long 为 64 bite,bool 为1 bit,且在 C# 中,bool类型量不能隐式转换为数值类型。
C# 布尔类型转换相对麻烦,如下:- class MyApp
- {
- static void Main() {
- bool a = true;
- bool b = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
-
- int aInt = Convert.ToInt32(a);
- long bInt = Convert.ToInt64(b);
- Console.WriteLine($"{aInt}, {bInt}");
- }
- }
复制代码 而 bool 类型自带了 ToString 方法
C# 在4.0 之后引入了 dynamic 关键字,意在模仿弱类型语言。
注意:浮点值不要用来进行 == 比较
2.2.2 类型在C#中的作用
一个C#类型中所包含的信息有:
- 存储次类型变量所需要的内存空间大小
- 此类型值可表示的最大、最小值范围
- 此类型所包含的成员(如方法、属性、事件等)
获取 Property(属性)信息和方法名,示例代码:- using System; // Type 类使用using System.Reflection; // PropertyInfo 和 MethodInfo 需要using System.Windows.Forms;namespace TypeSample{ internal class Program { static void Main(string[] args) { Type myType = typeof(Form); Console.WriteLine(myType.FullName); // System.Windows.Forms.Form Console.WriteLine(myType.BaseType.FullName); PropertyInfo[] pInfos = myType.GetProperties(); MethodInfo[] methodInfos = myType.GetMethods(); foreach (PropertyInfo pi in pInfos) // 拿到所有的property信息 {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(pi); } foreach (MethodInfo method in methodInfos) // 拿到所有的方法名 {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(method.Name); } // 在反射中,可以拿到property和 method name,那么就可以进行访问和调用 } }}
复制代码 而在反射中,可以拿到 property 和 method name,那么就可以进行访问和调用。
- 此类型由何基类派生而来
- 程序运行的时候,此类型的变量分配在内存的什么位置
- 使用 Performance Monitor 查看进行的堆内存使用量
- 关于内存泄漏
栈溢出
在 C# 中使用不安全的代码
在 Visual Studio 中需要进行设置:Project --> 当前工程名 Properties --> Build --> General --> Unsafe code 打勾,然后才能使用不安全代码- namespace StackoverflowSample{ internal class Program { static void Main(string[] args) { unsafe {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>int* ptr = stackalloc int[9999999]; // 栈溢出的代码 } } }}
复制代码 堆内存分配
在这里使用一个 Form 的例子,单击按钮创建一个列表,列表元素都是 Form,总共20000个,然后使用 Performance Monitor 观察内存使用情况:
MainWindow.xaml.cs- using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace HeapSample{ /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } List windowList; private void Button1_Click(object sender, RoutedEventArgs e) { windowList = new List(); for (int i = 0; i < 20000; i++) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Window win = new Window();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>windowList.Add(win); } } private void Button2_Click(object sender, RoutedEventArgs e) { windowList.Clear(); // 释放内存 } }}
复制代码 MainWindow.xaml- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>
复制代码 <img alt="image-20231216114714262" > 构建此程序,然后执行构建后的可执行文件。使用 Window + R 键 ,输入 perfmon,打开性能监视器,观察我们刚才所运行窗口程序的内存消耗情况。
如下是我点击三次 Consume Memory 得到的内存示意图:
然后点击 Release Memory,发现并不会立马就释放内存。此时程序会在整体内存很吃紧的情况下,gc 才回收内存,所以不会看到曲线立马回落。
使用性能监视器监视当前进程内存消耗情况:Process --> Private Bytes --> 要监视的进程名称 --> 添加
然后会发现,红线始终在顶上,说明这时候图表纵坐标分度太小,双击刚才添加的进程名称,在弹框中选择 图表,然后将 垂直比例 改为 1024,如果还是很高,则改为 2048,然后点击 “确定” 来应用:
- 此类型允许的操作(运算):涉及到后期的手动重载运算
程序的静态和动态:当程序还没运行的时候,称作静态时期;而当代码运行的时候,则是动态时期。和静态语言与动态语言类型中的“静态/动态是不一样的。
2.2.3 C# 的类型系统
C# 的五大数据类型
- 类(Classes):如 Windows, Form, Console, String
- 结构体(Structures):如:Int32,Int64, Single,Double
- 枚举(Enumerations):如 HorizontalAlignment,Visibility
- 接口(Interfaces)
- 委托(Delegates)
示例代码:- using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace TypeInCsharp{ internal class Program { static void Main(string[] args) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Type myType = typeof(Form); // 查看类的具体属性名称 Console.WriteLine(myType.FullName); // System.Windows.Forms.Form // 查看是不是类 Console.WriteLine(myType.IsClass); // True // 查看是不是值类型 Console.WriteLine(myType.IsValueType); // False // 枚举类型的应用 Form f = new Form(); f.WindowState = FormWindowState.Maximized; f.ShowDialog(); } }}
复制代码 下面是 FormWindowState 的实现:
C# 类型的派生谱系
问:C# 里面有哪几种数据类型?
- C# 中分为引用类型和值类型两种。引用类型有:类、接口、委托;值类型有:结构体、枚举。引用类型和值类型的基类都为 object
注意:上面图片中右侧黑色关键字:不是具体的数据类型,我们要使用这些关键字,定义自己的数据类型。蓝色关键字都是最常用的基本数据类型。
变量、对象和内存
什么是变量
- 表面来看,变量的用途是存储数据
- 实际上,变量表示了存储位置,并且每个变量都有一个类型,以决定什么样的值能够存入变量
- 变量共分为七种
- 静态变量,实例变量(成员变量,字段),数组元素,值参数,引用参数,输出形参,局部变量
- 下一的变量指局部变量,因为其他种类的变量都有自己的约定名称
- 变量的声明
- 有效的修饰符组合(可选) 类型 变量名 初始化器(可选)
示例代码:- using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices.WindowsRuntime;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace TypeInCsharp{ internal class Program { static void Main(string[] args) { // 变量类型 int[] array = new int[100]; // 声明长度为100的数组,默认都为零值 for (int i = 0; i < array.Length; ++i) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine($"{array[i]}"); } Student s = new Student(); // double res1 = s.Add(1, 2); // 编译错误:CS1620 double x = 1, y = 2; double res1 =s.Add(ref x, ref y); Console.WriteLine(res1); } } class Student { // 静态变量(静态字段) public static int Amount; // 非静态变量(成员/字段) public int Age; public string Name; // 引用参数变量 public double Add(ref double x, ref double y) { return x + y; } }}
复制代码变量 = 以变量名所对应的内存地址为起点、以其数据类型所要求的存储空间为长度的一块内存区域
值类型的变量
- 以四种结构体类型 byte/sbyte/short/ushort 为例
- byte:1 byte,包含 8 bit,可以表示的范围:0 ~ 28-1
- sbyte:1 byte,包含 8 bit,可以表示的范围:-27 ~ 27-1
- short:2 byte,包含 16 bit,可以包含的范围:-215 ~ 215-1
- ushort:2 byte,包含 16 bit,可以包含的范围:0 ~ 216-1
下面是常见C#基本类型的宽度:
有符号的负数表示:正值按位取反,然后再加1,示例:
十进制: 1000
二进制表示(short):0000 0011 1110 1000
十进制: -1000
二进制表示(short):
对1000按位取反: 1111 1100 0001 0111
<Window x:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EventSample"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
</Grid>
</Window>+1: 1111 1100 0001 1000
在 linqpad 中运行下面代码,可以打印出转为2进制的short变量:- short s = -1000;
- string str = Convert.ToString(s, 2);
- Console.WriteLine(str);
- // int 类型示例
- int aInt = -1000;
- string intStr = Convert.ToString(aInt, 2);
- Console.WriteLine(intStr);
复制代码
可以看到,无论是整型,还是短整型,都满足上述负数的表示规则
- 值类型没有实例,所谓的“实例”与变量合而为一
引用类型的变量与实例
- 引用类型变量与实例的关系:引用类型变量里存储的数据是对象的内存地址
局部变量是在栈上分配内存,实例变量在堆上分配内存
变量的默认值:零值,而且局部变量需要显示赋值,否则编译器将报错
装箱与拆箱
装箱(Boxing):
装箱是指将值类型转换为引用类型的过程。在装箱时,值类型的实例被包装在一个对象中(通常是 System.Object 类型的实例),从而使其可以存储在引用类型的变量中。- int intValue = 42;
- object boxedValue = intValue; // 装箱
复制代码 在这个例子中,intValue 是一个值类型(int),通过将其赋值给 boxedValue,发生了装箱,intValue 被包装在一个 object 类型的实例中。
装箱涉及了一次值的拷贝,从栈上值类型的值拷贝到堆上。拆箱与装箱相反,但也涉及到一次值的拷贝。
装箱和拆箱都会损失程序的性能
拆箱(Unboxing):
拆箱是指将引用类型转换回值类型的过程。在拆箱时,存储在引用类型中的值被提取并转换为原始的值类型。- object boxedValue = 42;
- int intValue = (int)boxedValue; // 拆箱
复制代码 在这个例子中,boxedValue 是一个引用类型,通过将其转换为 int,发生了拆箱,boxedValue 中的值被提取并转换为原始的 int 类型。
2.3 方法
其他和 C++ 中相同的地方就没必要记笔记了,在这里只记录值得记的信息。
2.3.1 构造器
构造器是类型的成员之一,狭义的构造器被称作“实例构造器”。当我们没有为类声明构造器时候,编译器会自动生成一个构造器。- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace MethodSample1
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s = new Student(128129, "Yuzu");
- Student s1 = s; // s1 为s的引用,这里没有调用构造函数,和C++不同,要注意!
- s.PrintInfo(); // Name: Yuzu, ID: 128129
- s1.Name = "Neko";
- s1.ID = 128128;
- s.PrintInfo(); // Name: Neko, ID: 128128
- s1.PrintInfo(); // Name: Neko, ID: 128128
- Student s2 = new Student(s); // s2 为深拷贝,不是s的引用,调用了自定义的构造器
- s2.Name = "Anya";
- s2.PrintInfo(); // Name: Anya, ID: 128128
- s.PrintInfo(); // Name: Neko, ID: 128128
- }
- }
- public class Student
- {
- public int ID;
- public string Name;
- public Student(int _ID, string _Name)
- { // 带参数的构造器,禁止无参构造
- this.ID = _ID;
- this.Name = _Name;
- }
- public Student(Student input)
- { // 重载了构造器
- this.ID = input.ID;
- this.Name = input.Name;
- }
- public void PrintInfo()
- {
- Console.WriteLine("Name: {0}, ID: {1}", Name, ID);
- }
- }
- }
复制代码 构造新对象,如果想要深拷贝,就要使用 new 操作符进行构造。C# 中 = 不能重载,这就意味着不能 自定义 = 构造对象。
编译运行结果:
2.3.2 方法重载
方法重载的作用是适应调入时候传入的参数
方法签名(Method Signature):方法的名称、类型参数的个数和它的每一个形参(从左到右的顺序)的类型和种类(值、引用和输出组成)。方法签名不包含返回类型。
示例:- using System.Data.Common;
- namespace OverloadSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Hello, World!");
- }
- }
- class Calculator {
- public int Add(int x, int y) {
- return x + y;
- }
- // 不是重载,重载不看返回类型
- //public double Add(int x, int y) {
- // return x + y;
- //}
- public double Add(double x, double y) {
- return x + y;
- }
- public double Add(double x, double y, double z) {
- return x + y + z;
- }
- public int Add<T>(T x, T y) { // T 为类型形参
- //...
- }
- }
- }
复制代码 重载决策:即选择到底调用哪一个重载,用于在给定了参数列表和一组候选函数成员的情况下,选择一个最佳函数成员来事实调用。C#中的重载决议没有C++中那么复杂,相对好理解很多。
2.3.3 Debug 方法讲解
示例代码如下:- namespace DebugExample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- double circleArea = Calculator.GetCircleArea(100);
- double cylinderVol = Calculator.GetCylinderVolume(100, 30);
- double coneVol = Calculator.GetConeVolume(100, 20);
- Console.WriteLine(circleArea);
- Console.WriteLine(cylinderVol);
- Console.WriteLine(coneVol);
- }
- }
- public class Calculator
- {
- public static double GetCircleArea(double r)
- {
- return Math.PI * Math.Pow(r, 2);
- }
- public static double GetCylinderVolume(double r, double h)
- {
- return GetCircleArea(r) * h;
- }
- public static double GetConeVolume(double r, double h)
- {
- return 1.0 / 3.0 * GetCylinderVolume(r, h);
- }
- }
- }
复制代码 在第 9 行添加一个断点,然后开启调试:
上面的三种debug方式:
- step into(F11):逐渐深入调试,进入每一层调用栈,这是最细腻的调试方式,一般用于仔细寻找错误
- step over(F10):直接获取调用结果,不进入调用栈
- step out(Shift + F11):跳出,返回到上一层调用栈
实际debug过程中,我们一般三种方式混合使用,前两者使用的更多一些。上面截图右下角可以看到调用栈信息,左下角可以观察当前变量的值
方法的调用与栈
这部分和 C++ 的相同(绝大部分语言中也是这样),即每调用一层,栈压入一次,调用结束,就弹出,当所有的栈都弹出了,则内存中所有的调用栈就清空了。C# 中参数入栈规则是:谁调用,谁压栈,谁调用,谁管理参数。参数入栈规则:先压入左侧参数,后压入右侧参数。而在C++中行为是未定义的,和编译器的具体实现有关。
函数的返回值一般存在寄存器中,如果存不下,则存在内存中。最终的返回值会被变量从寄存器中拿出,存在内存中。
2.4 操作符
C# 操作符概览:
从上往下优先级依次降低。计算机语言中的操作符不能脱离与它相关联的数据类型。
= 的运算顺序:从右往左计算,而其他数学运算符的运算顺序为从左往右。
同一优先级运算顺序:- class MyProgram
- {
- static void Main(string[] args) {
- int x = 100;
- int y = 200;
- int z = 300;
-
- x += y += z;
- Console.WriteLine(x); // 600
- Console.WriteLine(y); // 500
- Console.WriteLine(z); // 300
- }
- }
复制代码 2.4.1 委托的简单示例示例
- using System;
- using System.Collections.Generic;
- namespace OperatorExample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Calculator cal = new Calculator();
- Action ac = new Action(cal.PrintHello);
- ac(); // 调用被管理的方法
- }
- }
- public class Calculator {
- public double Add(double x, double y) {
- return x + y;
- }
-
- // 无返回值且无参数的方法
- public void PrintHello() {
- Console.WriteLine("Hello!");
- }
- }
- }
复制代码 Action 是一个简单的委托类型,它要求传入参数是一个无返回值、无参数的方法。委托的作用类似于C++中的类成员指针,可以通过类的成员指针访问类中的数据成员和函数成员。
2.4.2 访问数组与字典元素
- using System;using System.Collections.Generic;namespace OperatorExample{ internal class Program { static void Main(string[] args) { // 访问数组中的元素 int[] myIntArray = new int[] { 1, 2, 3, 4, 5 }; // [] 是初始化器 for (int i = 0; i < myIntArray.Length; i++) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(myIntArray[i]); } // 访问字典中的元素 Dictionary keyValuePairs = new Dictionary(); for (int i = 0; i < 100; ++i) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>string name = "stu_" + i.ToString();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Student stu = new Student(name, i);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>keyValuePairs.Add(name, stu); } Student obj = keyValuePairs["stu_99"]; Console.WriteLine(obj.ID); // 99 foreach(string name in keyValuePairs.Keys) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine($"Student Name : {keyValuePairs[name].Name}, Student ID : {keyValuePairs[name].ID}"); } } } class Student { public string Name; public int ID; public Student(string _Name, int _ID) { this.Name = _Name; this.ID = _ID; } }}
复制代码 使用 foreach 循环可以快捷的访问字典中的元素。如上述代码的第28行。
2.4.3 typeof 和 default 操作符
typeof 可以获取类型信息,如:- class MyProgram
- {
- static void Main(string[] args) {
- Type typeInfo = typeof(int);
- Console.WriteLine(typeInfo.Namespace);
- Console.WriteLine(typeInfo.FullName);
- Console.WriteLine(typeInfo.Name);
-
- int count = typeInfo.GetMethods().Length;
- foreach (var ms in typeInfo.GetMethods())
- {
- Console.WriteLine(ms.Name);
- }
- Console.WriteLine(count);
- }
- }
复制代码 部分编译运行结果:
default 操作符作用:设定当前类型的值为其默认零值,如果是引用类型,则设定为空值 null- namespace MyNameSpace
- {
- class Student
- {
- // ...
- }
- class MyProgram
- {
- static void Main(string[] args)
- {
- int aInt = default(int); // 0
- Student s = default(Student); // null
- Console.WriteLine(s == null); // True
- // Console.WriteLine(s is null); // True
- }
- }
- }
复制代码 2.4.4 new 操作符
变量类型根据是否显示注明类型,分为显式类型变量和隐式类型变量。隐式类型变量:要使用 var 声明- var x = 32; //x: int
- var x = 32L; //x: long
复制代码 new 操作符会创建实例,并调用类的实例构造器,从内存上创建相应区域用于存放该实例,并返回该内存地址给变量(如果有=)。
new 操作符除了可以访问构造器之外,还可以访问初始化器,如:- using System;
- using System.Windows.Forms;
- namespace NewOperatorExample
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- Form f = new Form() { Text = "Hello" };
- f.ShowDialog();
- }
- }
- }
复制代码 编译运行结果:
将源代码进行修改,添加:FormBorderStyle = FormBorderStyle.SizableToolWindow; 可以取消最大化和最小化按钮,这就是初始化器的作用:
并不是创建所有的实例都要调用 new 操作符。
为匿名类型创建对象
即创建类型的时候使用 var 声明,而不给出具体类型:- using System;
- using System.Windows.Forms;
- namespace AnonymousType
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- // 匿名类型:person
- var person = new { Name = "Yuzu", Age = 99 };
- Console.WriteLine(person.Name);
- Console.WriteLine(person.Age);
- Type t = person.GetType(); // 获取类型名称
- Console.WriteLine(t.Name);
- }
- }
- }
复制代码 编译运行结果:
可以访问到其中的数据,可以看到这个名称很奇怪,它是一个泛型类。
注意:new 操作符功能强大,但是不能随意使用,因为使用 new 创建的对象,它的实例和它的类之间就形成了紧密的耦合,这其实是有潜在风险的。而采用“依赖注入”的设计模式,可以降低耦合。
我们在编写代码的时候,要遵循:高内聚,低耦合的原则。
隐藏父类方法
使用 new 操作符可以隐藏父类的方法
如下,CsStudent 继承了 Student 类,在 CsStudent 中要对方法 PrintInfo 进行隐藏,使得对象调用同名方法时候调用的是子类的方法,而非父类的:- using System;
- using System.Windows.Forms;
- namespace HiddenBaseMethod
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- CsStudent cs1 = new CsStudent() { Name = "Yuzu", ID = "A12345"};
- cs1.PrintInfo();
- }
- }
- class Student
- {
- public string Name;
- public string ID;
- public void PrintInfo()
- {
- Console.WriteLine($"Name: {Name}, ID:{ID}");
- }
- }
- class CsStudent : Student
- {
- // new 作为修饰符,可以对父类同名方法进行隐藏
- new public void PrintInfo() {
- Console.WriteLine($"CS Student Name: {Name}, ID:{ID}");
- }
- }
- }
复制代码 编译运行结果:
注意:override 关键字只能用于虚函数中,且在 C# 中没有纯虚函数,但是有功能类似的抽象类,使用 abstract 关键字修饰。
使用 override 修饰示例:- using System;
- using System.Windows.Forms;
- namespace HiddenBaseMethod
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- CsStudent cs1 = new CsStudent() { Name = "Yuzu", ID = "A12345"};
- cs1.PrintInfo();
- }
- }
- class Student
- {
- public string Name;
- public string ID;
- // 只用使用 virtual 修饰的方法,子类才能重写
- public virtual void PrintInfo()
- {
- Console.WriteLine($"Name: {Name}, ID:{ID}");
- }
- }
- class CsStudent : Student
- {
- // override 作为修饰符,表示对父类同名方法进行重写
- public override void PrintInfo() {
- Console.WriteLine($"CS Student Name: {Name}, ID:{ID}");
- }
-
- }
- }
复制代码 2.4.5 checked 和 unchecked
checked 和 unchecked 是用来检测整型变量数值转换和求值导致的溢出异常的。示例:- namespace CheckedAndUnchecked{ internal class Program { static void Main(string[] args) { // checked 和 unchecked 用法 uint a = uint.MaxValue; string binA = Convert.ToString(a, 2); // 转为二进制字符串 Console.WriteLine("{0} {1}", a, binA); // 4294967295 11111111111111111111111111111111 try {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>uint b = checked(a + 1); // 发生溢出异常<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("{0} {1}", b, Convert.ToString(b, 2)); } catch (OverflowException e) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Overflow! Msg : {0}", e); } uint x = uint.MinValue; try {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>uint y = unchecked(x - 1); // 不再检查异常,发生溢出也继续执行下一行代码<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("{0}, {1}", y, Convert.ToString(y, 2)); } catch (OverflowException e) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Overflow! Msg : {0}", e); } } }}
复制代码 编译运行结果:
C# 默认采用的是 unchecked 模式。下面这种可以对模块批量进行设置:- checked{
- // ... expression
- }
复制代码 2.4.6 delegate 操作符
delegate 操作符可以用来声明匿名方法(这种用法现在已经被抛弃,因为使用 lambda 表达式会更加简单),这里只是用作示例:
MainWindow.xaml.cs- using System;
- using System.Windows;
- namespace DelegateExample
- {
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- // 使用 delegate 挂载事件
- this.myButton.Click += delegate (object sender, RoutedEventArgs e) { this.myTextBox.Text = "馬鹿馬鹿!"; };
- }
- // 最传统的,另外定义一个事件的函数,然后调用
- //private void MyButton_Click(object sender, RoutedEventArgs e)
- //{
- // this.myTextBox.Text = "馬鹿馬鹿!";
- //}
- }
- }
复制代码 这上面的就是窗口的事件处理函数,挂载到了按钮 myButton 的点击事件,先前我们最常规的做法就是另外写一个函数,然后进行调用。现在可以使用 delegate 来声明匿名方法用以简化代码,但是不建议这么写,建议使用匿名函数将第 17 行代码写成如下形式:- // 使用 lambda 表达式挂接事件
- this.myButton.Click += (object sender, RoutedEventArgs e) => { this.myTextBox.Text = "馬鹿馬鹿!"; };
复制代码 MainWindow.xaml- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window><Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window><Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window><Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>
复制代码 2.4.7 sizeof 操作符
sizeof 运算符只能用于基本数据类型变量所占的字节数大小(除了 string 和 object,因为 sizeof 只能用来获取结构体数据类型在内存中占的字节数,而 string 和 object 不是结构体数据类型)。
示例:- using System;
- using System.Windows.Forms;
- namespace AnonymousType
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- // 默认情况下
- Console.WriteLine(sizeof(int)); // 4
- Console.WriteLine(sizeof(long)); // 8
- Console.WriteLine(sizeof(double)); // 8
- Console.WriteLine(sizeof(float)); // 4
- Console.WriteLine(sizeof(decimal)); // 16
- Console.WriteLine(sizeof(byte)); // 1
- Console.WriteLine(sizeof(char)); // 2
- Console.WriteLine(sizeof(short)); // 2
- Console.WriteLine(sizeof(bool)); // 1
- // 自定义数据类型:必须写在 unsafe 中
- unsafe
- {
- int x = sizeof(Student); // 16
- Console.WriteLine(x);
- }
- }
-
- }
-
- struct Student{
- int ID;
- long Score;
- }
- }
复制代码 至于为什么上面的 struct 尺寸为 16 字节,涉及到了内存对齐相关知识,C# 中内存对齐机制比C++中还要不明晰,默认的规则粗略总结为:结构体在内存中所占大小一般为(单位:字节):2、4、8、8*n(n为整数,且大于等于1)。当内存大于8,则直接取最近的8的倍数。
2.4.8 -> 操作符
-> 是指针访问操作符,和C++中是一样的,下面是一个小例子:- namespace Ptr
- {
- class MyProgram
- {
- static void Main(string[] args)
- {
- Student s = new Student(12888, "Yuzu");
- unsafe
- {
- Student* ptr = &s;
- ptr->Name = "Ayaka";
- Console.WriteLine($"{ptr->Name} : {ptr->ID}");
- }
- }
- }
- public class Student
- {
- public double ID;
- public string Name;
- public Student(double _ID, string _Name)
- {
- this.ID = _ID;
- this.Name = _Name;
- }
- }
- }
复制代码 编译运行结果:注:C# 中指针的使用十分有限,并且是“消毒”过的。没有顶层 const 和底层 const 等C++拥有的奇怪特性,真是让人快乐……
其他的 *x 和 &x 在 C++ 中常用,但是在 C# 中均不常用。
2.4.8 逻辑运算符
常见的逻辑运算都和C++中一致,条件运算(&& ||)照样使用短路逻辑,建议不要在代码中使用这个特性,而要尽量避开,很容易造成不易察觉的 bug。
逻辑非:!实际应用:
检查传入的构造参数是否符合要求,如下面的参数中,如果 string 类型的名称为空,则抛出异常,停止构造- namespace LogicNotExample{ class MyProgram { static void Main(string[] args) { Student s = new Student("", 12888); // 传入空字符串 Console.WriteLine(s.Name); } } public class Student { public string Name; public double ID; public Student(string _Name, double _ID) { // 检查传入的字符串是否为 null 或者空 if (!string.IsNullOrEmpty(_Name)) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Name = _Name;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.ID = _ID; } else {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>throw new ArgumentException("_Name is Empty"); } } }}
复制代码 运行结果:
2.5 数据类型与转换
数据类型转换是我们经常用到的,从最常见的需求:我们在命令行输入两个数,然后在控制台打印出他们相加的结果:- namespace ReadLineExample{ internal class Program { static void Main(string[] args) { string str1 = Console.ReadLine() ?? "0"; // 若为null,则赋值为"0" string str2 = Console.ReadLine() ?? "0"; if (!string.IsNullOrWhiteSpace(str1) && !string.IsNullOrWhiteSpace(str2)) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>double db1 = Convert.ToDouble(str1);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>double db2 = Convert.ToDouble(str2);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(db1 + db2); } } }}
复制代码 在这里使用了 Convert 类,该类可以直接调用其静态方法,实现各种类型之间的转换。查询文档可知,Convert 类的方法全部为静态方法。
2.5.1 类型转换
隐式类型转换
有三种:
- 不丢失精度的转换
- 子类向父类的转换
示例:定义一个动物类 Animal,Human 继承 Animal,Teacher 继承 Human。继承之后,子类就拥有了父类所有的方法和字段- namespace ConversionSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // 1.隐式类型转换
- Teacher t1 = new Teacher();
- t1.Teach();
- t1.Eat();
- t1.Think();
- // 子类向父类转换
- Human h = t1; // 子类t1向父类转换,h 是 t1 的引用
- h.Think();
- h.Eat();
- //h.Teach(); // 父类没有这个方法
- }
- }
- class Animal
- {
- public void Eat()
- {
- Console.WriteLine("I'm eating!");
- }
- }
- class Human : Animal
- {
- public void Think()
- {
- Console.WriteLine("I'm thinking!");
- }
- }
- class Teacher : Human
- {
- public void Teach()
- {
- Console.WriteLine("I'm teaching!");
- }
- }
- }
复制代码 编译运行结果:- I'm teaching!
- I'm eating!
- I'm thinking!
- I'm thinking!
- I'm eating!
复制代码 可以看出来, h 是 t1 的引用,但是h的类型为 Human,只能使用 Human 中拥有的方法。
- 装箱
显式类型转换
- 有可能丢失精度(甚至发生错误)
- 拆箱
- 使用 Convert 类
- ToString 方法与各种数据类型的 Parse/TryParse 方法
示例代码:- namespace ConversionSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // 2.显式类型转换
- uint iNum = uint.MaxValue;
- ushort usNum = (ushort)iNum; // 丢失了精度,截断导致
- Console.WriteLine(iNum);
- Console.WriteLine(usNum);
- Console.WriteLine(Convert.ToString(iNum, 2).PadLeft(sizeof(uint) * 8, '0'));
- Console.WriteLine(Convert.ToString(usNum, 2).PadLeft(sizeof(ushort) * 8, '0'));
- uint iNum2 = 23453;
- Console.WriteLine(Convert.ToString(Convert.ToString(iNum2, 2).PadLeft(sizeof(uint) * 8, '0')));
- // Parse / TryParse 方法
- string s = Console.ReadLine();
- // int num1 = int.Parse(s); // Parse(s) 中s格式不正确会抛出异常
- int num2;
- bool success = int.TryParse(s, out num2);
- if (success) { Console.WriteLine(num2); } else { return; }
- }
- }
- }
复制代码 PadLeft(sizeof(uint) * 8, '0')) 作用是当位数不足时候,左侧补齐0。
建议使用 type.TryParse() 方法,因为不会抛出异常,我们可以直接处理格式错误的情况。
显式类型转换的实现:
如我们定义了两个类,西游记应该都看过,一个石头经历很多年,然后变成了一只猴子。下面定义了两个类,一个 Stone 类和一个 Monkey 类,都有成员 Age,当石头过了 500 年,如果变成猴子,就成了 1 岁的猴子。
那么怎么实现猴子类和石头类之间的转换呢?还要将他们之间的年龄进行换算。这时候明显不能使用继承,因为继承是同属性的,而猴子类和石头,一个属于有机生命,一个属于无机物,自然不能是继承关系。这时候就要用到显式类型转换了:- namespace ExplicitConvertSample{ internal class Program { static void Main(string[] args) { Stone stone = new Stone("WuKong", 10000); Monkey m = (Monkey)stone; Console.WriteLine($"{m.Name} : {m.Age}"); } public class Stone { public string Code; public int Age; public Stone(string _Code, int _Age) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Code = _Code;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Age = _Age; } public static explicit operator Monkey(Stone stone) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Monkey m = new Monkey("Monkey "+stone.Code, stone.Age / 500);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>return m; } } public class Monkey { public string Name; public int Age; public Monkey(string _Name, int _Age) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Name = _Name;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Age = _Age; } } }}
复制代码 编译运行结果:
只需要少许修改,就可以使用隐式转换(不过看起来有些奇怪):
先将上述代码第 25 行:operator Monkey 的重载修饰符改为 implicit- public static implicit operator Monkey(Stone stone)
复制代码 然后调用处直接使用 = 即可,第 9 行可修改为:搞明白这个,我们就能写自定义类型转换方法了。注意,自定义的类型转换方法,要写在原类型中(如在本处,原类型为 Stone,而目标类型为 Monkey)。
在运算符中,有的符号在C++中能够重载,但是在C#不能重载,查看C#运算符是否能重载:https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/operator-overloading#overloadable-operators
2.5.2 == 与 is 与 as 操作符
== 在C#的行为与C++中没什么差别,且也可以像C++中那样进行重载,没什么特殊的。这里举一个无穷的示例,这里需要注意:无穷值不能由整型产生- namespace InfinitySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // 无穷大
- float flPositiveInfinity = float.PositiveInfinity;
- float flNegativeInfinity = float.NegativeInfinity;
- double dbPosInfinity = double.PositiveInfinity;
- double dbNegInfinity = double.NegativeInfinity;
- Console.WriteLine(dbPosInfinity);
- Console.WriteLine(dbNegInfinity);
- Console.WriteLine(flPositiveInfinity == null);
- }
- }
- }
复制代码 is 和 as 操作符的作用有些相似,这两个在C++中没有,要着重讲解下
is 操作符判断某对象是否由某类(或者其子类)构建所得,而 as 操作符则是判断某对象是否行为与某类生成的对象行为一致。
实际上,as 显式做了类型转换,若是转换不成功则返回 null,成功则返回一个引用,且不会抛出异常。
下面是一个示例:- namespace IsAsSample{ internal class Program { static void Main(string[] args) { // is 操作符:判断所属关系,即某实例或者返回值是否为某类型(或者其子类型),返回布尔值 Teacher t = new Teacher(); Console.WriteLine(t is Teacher); // True Console.WriteLine(t is Human); // True Console.WriteLine(t is Animal); // True Car c = new Car(); Console.WriteLine(c is Animal); // False object o = new Teacher(); if(o is Teacher) // True {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Teacher t1 = (Teacher)o;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>t1.Teach(); } // as 操作符:一定程度上替代 is:即判断某对象行为是否与某类型实例行为一致 object o1 = new Teacher(); Teacher? t2 = o1 as Teacher; // ? 表示 t2 可能为null,as 操作符做显式类型转换,即:将 o1 转为 Teacher 类型,若转换不成功则返回 null if (t2 != null) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>t2.Teach(); } } } class Animal { public void Eat() { Console.WriteLine("I'm eating!"); } } class Human : Animal { public void Think() { Console.WriteLine("I'm thinking!"); } } class Teacher : Human { public void Teach() { Console.WriteLine("I'm teaching!"); } } class Car { string Name; }}
复制代码 编译运行结果:
下面是文档中对 as 的解释:
The as operator explicitly converts the result of an expression to a given reference or nullable value type. If the conversion isn't possible, the as operator returns null. Unlike a cast expression, the as operator never throws an exception.
2.5.3 可空类型
可空类型(Nullable)即可指定一个类型为空值 null。如:- namespace NullableSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Nullable<int> num1 = null;
- Console.WriteLine(num1.HasValue);
- // 简写:?
- int? num2 = null;
- if (num2.HasValue) { Console.WriteLine(num2); }
- int res = num2 ?? 1; // null 值合并运操作符 ??
- Console.WriteLine(res);
- }
- }
- }
复制代码 Nullable 的简写为 T? ,如第 11 行所示,即当前变量取 null 值做保留,一般为后续使用。
第 15 行的 ?? 被称作 null 值合并运算符,格式:expression1 ?? expression2。如果左操作数 expression1 运算结果为 null,则返回右操作数- // ??(null 值合并运操作符):如果左操作数为 null,则返回右操作数
- int res = num2 ?? 1;
复制代码 2.6 表达式和语句
2.6.1 表达式
表达式英语为 Expression,下面是书籍 Programming Languages: Principles and Paradigms 对它的定义:
Expression, together with commands and declarations, are one of the basic components of every language, We can say that expressions are the essential component of every language.
An expression is a syntactic entity whose evaluation either produces a value or fails to terminate, in which case the expression is undefined.
C# 语言中对它的定义:
An expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace. Expressions can consist of a literal value, a method invocation, an operator and its operands, or a simple name. Simple names can be the name of a variable, type member, method parameter, namespace or type.
C# 中对表达式的分类:
- A value. Every value has a associated type
- A variable. Every variable has a associated type
- A namespace
- A method group, eg. Console.WriteLine,这是一组方法,重载决议(Overload Resolution)会选择具体调用哪个
- A null literal
- An Anonymous function
- A property access
- An event access
下面为如何使用事件访问器,在窗体加载时动态更改窗体的标题。
如新建一个 Form,如果发生了 Load 事件,则更换标题(Text 属性):- using System;using System.Windows.Forms;namespace EventAccessSample{ internal class Program { static void Main(string[] args) { Form myForm = new Form(); myForm.Text = "Hello"; // Load:加载事件,sender 为事件发起者,以object类型进行传输 myForm.Load += (object sender, EventArgs e) => {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Form form = sender as Form;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (form == null)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>form.Text = "New Title"; }; myForm.ShowDialog(); } }}
复制代码 第 13 行就访问了 myForm 的 Load 事件
myForm.Load += (object sender, EventArgs e) => { ... };:这一行代码订阅了窗体的Load事件。当窗体加载时,将执行括号内的代码块。使用 Lambda 表达式创建了一个匿名方法,该方法接受两个参数: sender 和 e,分别表示事件的发起者和事件参数。
- sender :是事件的发起者,以 object 类型传输。在这里,它被强制转换为 Form 类型,并赋值给 form 变量。
- e :是事件的参数,这里是 EventArgs 类型,表示不包含任何特定数据的事件参数。
- An indexer access
- Nothing. 对返回值为 void 的方法的调用
2.6.2 语句
语句在英语中翻译为 statement,下面是维基百科对它的定义:
In computer programming a statement is the smallest standalone element of an imperative programming language which expresses some action to be carried out. A program written in such a language is formed by a sequence of one or more statements. A statement will have internel components(eg. expressions).
语句是高级语言的语法,语句等价于一个或一组由明显逻辑关联的指令。
C# 中对语句的定义:
The actions that a program takes are expressed in statements. Common actions include declaring variables, calling methods, looping through collections, and branching to one or another block of code, depending on a given condition. The order in which statements are executed in a program is called the flow of control or flow of execution. The flow of control may vary every time that a program is running, depending on how the program reacts to input that it receives at run time.
C# 语言的语句除了能够让程序员“顺序地”(sequentially)表达算法思想,还能通过条件判断、跳转和循环等方式控制程序逻辑的走向。简而言之就是:陈述算法思想,控制逻辑走向,完成有意义的动作(action)。
C# 的语句由分号(;)结尾,但是以分号结尾的不一定都是语句。语句一定出现在方法体里。
如 using System; 就不是语句(这个叫 using 指令),类中字段的定义也不是语句。
Visual Studio 中反汇编工具的使用
打开x64_x86 Cross Tools Command Prompt for VS 2022,即开发者命令行工具。该工具随着 Visual Studio 一同安装的,然后打开它。或者直接在 Visual Studio 按 Control + `,也能直接打开开发者命令行工具。
输入 ildasm 即打开反汇编程序。然后点击左上角:文件 -- 打开,然后打开我们使用 Visual Studio 构建的可执行程序或者库文件。
常见语句类型
和C++中基本一致,这里只解释不一样的。复合语句在这里也被称作嵌套语句。下面是一个嵌入式语句:C# 中的 dangling-else 问题
如下面这种不清晰的代码,最后一个 else 匹配的究竟是哪一个 if ?- namespace FlowControlSample{ internal class Program { static void Main(string[] args) { string? input = Console.ReadLine(); double dbNum; bool pass = double.TryParse(input, out dbNum); if (pass)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (dbNum >= 60)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("PASS");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("FAILED"); } }}
复制代码 实际上是匹配的最近的 if,在这里是内层的 if,而 Visual Studio 会自动格式化代码(像上面这样),让代码看起来更清晰。
此外,我们应当尽量避免多层条件语句嵌套,这会让代码易读性十分差,且不利于后期维护。
在这里可以见到常见语言给 dangling-else 的解决方案:https://stackoverflow.com/questions/967511/how-do-different-languages-handle-the-dangling-else
switch 语句
switch 语句的语法:- switch(Expression)
- {
- case x:
- // code block
- break;
- case y:
- // code block
- break;
- default:
- // code block
- break;
- }
复制代码 上面语句中,表达式类型为 sbyte, byte, ushort, short, uint, int, long, ulong, bool, char, string 或 枚举类型,或者为对于上面某种类型的可空类型(nullable type),该类型就是 switch 语句的主导类型。
注意:
- switch 中的表达式不能使用任何浮点类型,否则编译器会报错!
- case 后面跟常量表达式,且类型要和 Expression 类型相同
- C# 中的 switch 语句不允许 fallthrough,默认要在 case 结束了添加 break,否则编译器会报错
C# 中 switch 的高级用法:模式匹配
示例代码:- namespace SwitchSample{ class MyProgram { static void Main(string[] args) { DisplayMeasurement(-4); // Output: Measured value is -4; too low. DisplayMeasurement(5); // Output: Measured value is 5. DisplayMeasurement(30); // Output: Measured value is 30; too high. DisplayMeasurement(double.NaN); // Output: Failed measurement. Console.WriteLine("Please input day number(eg. Monday, input '1'): "); string? d = Console.ReadLine(); WeekDay day; bool success = Enum.TryParse(d, out day); if (success) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>day--;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>switch (day)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> case outer) { break; } Console.Write($"{inner} "); } Console.WriteLine();}// Output:// 0// 0 1// 0 1 2// 0 1 2 3// 0 1 2 3 4
复制代码 continue :当前循环轮空,进入下一轮循环,如代码所示:- enum WeekDay : uint
- {
- Mon,
- Tues,
- Wed,
- Thur,
- Sat,
- Fri,
- Sun,
- }
复制代码 将上面的数字游戏进行修改,使它的流程变得更加合理:- namespace DoWhileSample{ internal class Program { static void Main(string[] args) { string? s1, s2; bool flag = true; uint score = 0; do {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Please input first number to continue or 'end' to stop.");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>s1 = Console.ReadLine() ?? "";<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if(s1.ToLower() == "end")<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> break;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("Please input second number");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> s2 = Console.ReadLine();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> int num1 = 0;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> int num2 = 0;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> int sum = 0;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 对最有可能出问题的参数进行异常捕获<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> try<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> num1 = int.Parse(s1);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> catch<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("First argument has problem! Restarting");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> continue;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> try<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> num2 = int.Parse(s2);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> catch<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("Second argument has problem! Restarting");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> continue;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> sum = num1 + num2;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> if (sum == 100)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> score++;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine($"Correct! {num1} + {num2} = {sum}, total score is {score}");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine("---------------------------------------------");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> flag = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine($"Wrong! {num1} + {num2} = {sum}");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine($"Your total score is {score}");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } while (flag); } }}
复制代码 for 语句
最佳使用场景:计数循环,即循环的次数是固定的。比起 do...while 语句,for 语句看起来更加简洁。- using System.ComponentModel;
- namespace TrySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Calculator calc1 = new Calculator();
- //int result = calc1.Add(null, "12") // System.ArgumentNullException
- //int result = calc1.Add("abc", "123"); // System.FormatException
- // int result = calc1.Add("99999999999", "9999999999"); // System.OverflowException
- int result = calc1.Add("12", "42");
- Console.WriteLine(result);
- }
- }
- class Calculator
- {
- public int Add(string input1, string input2)
- {
- int a = int.Parse(input1);
- int b = int.Parse(input2);
- return a + b;
- }
- }
- }
复制代码 for_initialization 只执行一次,但是要记得:最后一次,for_iteration 也会执行。
如下面是一个面试题,请问打印出来的 counter 值是多少?- namespace forSample{ internal class Program { static void Main(string[] args) { int counter = 0; for(; counter < 10; counter++) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>// do something } Console.WriteLine(counter); } }}
复制代码 因为当 counter = 9 的时候,counter < 10 依旧成立,此时循环体内代码再次执行,最后执行 counter++,然后 counter 的值就为 10 了。此时 10 < 10 明显不成立,于是跳出 for 循环,最后打印的 counter 值就是 10 了。
在实际开发中,不要将 counter 写在for循环外面,而是写在 for_initialization 处。
下面是使用 for 循环实现的一个九九乘法表:- using System.ComponentModel;
- namespace TrySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // ... 和上面一样
- }
- }
- class Calculator
- {
- public int Add(string input1, string input2)
- {
- int a = 0;
- int b = 0;
- try
- {
- a = int.Parse(input1);
- b = int.Parse(input2);
- }
- catch
- {
- Console.WriteLine("Your argument(s) have error!");
- }
- return a + b;
- }
- }
- }
复制代码 但是不能将两个属性同时设为 private,此时编译器会报错(和前面的 public 限定符功能违背)。注意区分这种从内部可访问的属性和只读属性的区别,只读属性是只有一个 getter,若是调用 setter,编译器会报错(因为没有 setter)。
动态计算属性的值
即属性的值和我们输入的变量有关,如在国内,一个学生没满 16 岁,是不能工作的,可以动态计算该学生是否能工作:- namespace PropertySample2{ internal class Program { static void Main(string[] args) { try {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Student s = new Student(12, "Yuzu");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("{1} Can Work: {0}", s.CanWork, s.Name);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Student s1 = new Student(22, "Akita");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("{1} Can Work: {0}", s1.CanWork, s1.Name); } catch (Exception ex) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(ex.Message); } } } class Student { public int Age { get; set; } // 简略的属性(包装器)写法,不会抛出任何异常 public string Name; public Student(int _Age, string _Name) { Age = _Age; Name = _Name; } // 根据输入值动态 public bool CanWork { get {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (Age >= 16)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return true;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } } }}
复制代码 编译运行结果:
这里的 CanWork 属性,就只是一个只读属性,只读属性只有 getter,没有 setter。
CanWork 会根据输入不同,产生不同的结果(类似动态方法)。
属性和字段的关系:
- 属性是字段的包装器,用来控制对字段的访问
- 一般情况下,属性都用于表示实体(对象或类型)的状态
- 建议:永远使用属性(而不是字段)来暴露数据,即字段永远是 private 或 protected 的
2.7.3 索引器
索引器(indexer)是一种成员,它使得对象能够用与数组相同的方式(即下标)来进行索引。
注:没有静态索引器这一说。其中较为复杂的就是索引器的定义:- namespace TrySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Calculator calc1 = new Calculator();
- int result1 = calc1.Add(null, "12"); // System.ArgumentNullException
- int result2 = calc1.Add("abc", "123"); // System.FormatException
- int result3 = calc1.Add("99999999999", "9999999999"); // System.OverflowException
- int result = calc1.Add("12", "42");
- Console.WriteLine(result);
- }
- }
- class Calculator
- {
- public int Add(string input1, string input2)
- {
- int a = 0;
- int b = 0;
- bool hasError = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- try
- {
- a = int.Parse(input1);
- b = int.Parse(input2);
- }
- catch (ArgumentNullException ane)
- {
- Console.WriteLine(ane.Message);
- hasError = true;
- }
- catch (FormatException fe)
- {
- Console.WriteLine(fe.Message);
- hasError = true;
- }
- catch (OverflowException oe)
- {
- Console.WriteLine(oe.Message);
- hasError = true;
- }
- catch (ArgumentException ae)
- {
- Console.WriteLine(ae.Message);
- hasError = true;
- }
- finally
- {
- if (hasError)
- {
- Console.WriteLine("Execution has error!");
- }
- else
- {
- Console.WriteLine("Done!");
- }
- }
- int result = a + b;
- return result;
- }
- }
- }
复制代码 这是 Student 类中的索引器定义。通过 this[string subject] 可以像数组一样访问对象。get 部分用于获取指定科目的分数,set 部分用于设置指定科目的分数。在 set 中,如果传递的值为 null,则抛出异常;否则,更新或添加对应科目的分数。
2.7.4 常量
常量可以加快程序的运行效率。
常量是针对类型而言的,没有“实例常量”这一说。而接近于实例常量这一概念的,可以用前面的 readonly 关键字修饰只读实例。
各种只读的应用场景:
- 为了提高程序可读性和执行效率 -- 常量
- 为了防止对象的值被修改 -- 只读字段
- 向外暴露不允许修改的数据 -- 只读属性(静态或者非静态),功能与常量有一定重叠
- 当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)-- 静态只读字段
2.7.5 参数
值参数
值类型
不带修饰符的形参就是值参数。
示例代码:- namespace TrySample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Calculator calc1 = new Calculator();
-
- // 处理抛出的异常
- int result3 = 0;
- try
- {
- result3 = calc1.Add("99999999999", "9999999999"); // System.OverflowException
- }
- catch (OverflowException oe)
- {
- Console.WriteLine(oe.Message);
- }
- Console.WriteLine(result3);
- }
- }
- class Calculator
- {
- public int Add(string input1, string input2)
- {
- int a = 0;
- int b = 0;
- bool hasError = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- try
- {
- // ...
- }
- catch (OverflowException oe) // 可以不要这里的 oe
- {
- // Console.WriteLine(oe.Message);
- hasError = true;
- throw oe;
- }
- // ...
- finally
- {
- if (hasError)
- {
- Console.WriteLine("Execution has error!");
- }
- else
- {
- Console.WriteLine("Done!");
- }
- }
- int result = a + b;
- return result;
- }
- }
- }
复制代码 引用类型
- 丢弃原有对象,创建新的对象
示例代码:- try
- {
- //...
- }
- catch(OverflowException) // 不需要标识符
- {
- hasError = true;
- throw; // 直接抛出异常
- }
复制代码 编译运行结果:- namespace HundredSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- string s1, s2;
- bool flag = true;
- uint score = 0;
- while (flag)
- {
- Console.WriteLine("Please input two numbers, when the sum equals 100, +1 point.");
- s1 = Console.ReadLine();
- s2 = Console.ReadLine();
- int sum = 0;
- try
- {
- int num1 = int.Parse(s1);
- int num2 = int.Parse(s2);
- sum = num1 + num2;
- if (sum == 100)
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }score++;
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Correct! {num1} + {num2} = {sum}, total score is {score}");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine("---------------------------------------------");
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }flag = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Wrong! {num1} + {num2} = {sum}");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Your total score is {score}");
- }
- }
- catch(OverflowException oe)
- {
- Console.WriteLine(oe.Message);
- }
- catch (FormatException fe)
- {
- Console.WriteLine(fe.Message);
- }
- catch (ArgumentNullException ane)
- {
- Console.WriteLine(ane.Message);
- }
-
- }
- }
- }
- }
复制代码 我们再将上面的代码修改下,将 SomeMethod 中的形式参数修改为和传入参数相同:- namespace DoWhileSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- string s1, s2;
- bool flag = true;
- uint score = 0;
- do
- {
- Console.WriteLine("Please input two numbers, when the sum equals 100, +1 point.");
- s1 = Console.ReadLine();
- s2 = Console.ReadLine();
- int sum = 0;
-
- try
- {
- int num1 = int.Parse(s1);
- int num2 = int.Parse(s2);
- }
- catch (OverflowException oe)
- {
- Console.WriteLine(oe.Message);
- }
- catch (FormatException fe)
- {
- Console.WriteLine(fe.Message);
- }
- catch (ArgumentNullException ane)
- {
- Console.WriteLine(ane.Message);
- }
-
- sum = num1 + num2;
- if (sum == 100)
- {
- score++;
- Console.WriteLine($"Correct! {num1} + {num2} = {sum}, total score is {score}");
- Console.WriteLine("---------------------------------------------");
- }
- else
- {
- flag = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- Console.WriteLine($"Wrong! {num1} + {num2} = {sum}");
- Console.WriteLine($"Your total score is {score}");
- }
- } while (flag);
- }
- }
- }
复制代码 编译运行结果:- for (int outer = 0; outer < 5; outer++)
- {
- for (int inner = 0; inner < 5; inner++)
- {
- if (inner > outer)
- {
- break;
- }
- Console.Write($"{inner} ");
- }
- Console.WriteLine();
- }
- // Output:
- // 0
- // 0 1
- // 0 1 2
- // 0 1 2 3
- // 0 1 2 3 4
复制代码 从结果可以得到,虽然名字不同,但是两个对象确实并不相同。
注意:
- 值参数创建变量的副本
- 对值参数的操作永远不影响变量的值。
- 只操作对象,不创建新的对象
对象仍旧是原本的对象,但对象内的值(字段、属性)已经发生改变。
示例代码:- for (int i = 0; i < 5; i++)
- {
- Console.Write($"Iteration {i}: ");
-
- if (i < 3)
- {
- Console.WriteLine("skip");
- continue;
- }
-
- Console.WriteLine("done");
- }
- // Output:
- // Iteration 0: skip
- // Iteration 1: skip
- // Iteration 2: skip
- // Iteration 3: done
- // Iteration 4: done
复制代码 编译运行结果:- namespace DoWhileSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- string? s1, s2;
- bool flag = true;
- uint score = 0;
- do
- {
- Console.WriteLine("Please input first number to continue or 'end' to stop.");
- s1 = Console.ReadLine() ?? "";
- if(s1.ToLower() == "end")
- {
- break;
- }
- else
- {
- Console.WriteLine("Please input second number");
- s2 = Console.ReadLine();
- int num1 = 0;
- int num2 = 0;
- int sum = 0;
- // 对最有可能出问题的参数进行异常捕获
- try
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }num1 = int.Parse(s1);
- }
- catch
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine("First argument has problem! Restarting");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }continue;
- }
- try
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }num2 = int.Parse(s2);
- }
- catch
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine("Second argument has problem! Restarting");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }continue;
- }
- sum = num1 + num2;
- if (sum == 100)
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }score++;
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Correct! {num1} + {num2} = {sum}, total score is {score}");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine("---------------------------------------------");
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }flag = namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Wrong! {num1} + {num2} = {sum}");
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }Console.WriteLine($"Your total score is {score}");
- }
- }
- } while (flag);
- }
- }
- }
复制代码 引用参数
- 值类型的引用参数
示例代码:- for(for_initialization; for_condition; for_iteration) {//...}
复制代码 引用参数在声明和调用的时候都要显式使用 ref 显式注明!并且一般要利用引用参数的副作用才这么写。
- 引用类型的引用参数:创建新对象
示例代码:- namespace forSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- int counter = 0;
- for(; counter < 10; counter++)
- {
- // do something
- }
- Console.WriteLine(counter);
- }
- }
- }
复制代码 编译运行结果:- namespace MulTableSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- int i, j;
- for (i = 1; i <= 9; ++i)
- {
- for(j = 1; j < i; ++j)
- {
- Console.Write($"{j} x {i} = {i * j}\t");
- }
- Console.WriteLine($"{j} x {i} = {i * j} ");
- }
- }
- }
- }
复制代码注意:
- 引用参数不创建变量的副本
- 使用 ref 修饰符显式指出 -- 此方法的副作用是改变实际参数的值
- 引用类型引用参数:只改变对象
还有一种较为少见的引用类型引用参数使用方式:不创建新对象,只改变对象值,此时值参数(见上面的值参数第三个示例,只修改对象,但不创建对象)在效果上没有不同,但是机理不一样。
- using System.Collections.Generic;
- using System.Collections;
- using System;
- namespace ForeachSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // C# 中的迭代器
- int[] intArr = { 1, 2, 3, 4, 5 };
- IEnumerator enumerator = intArr.GetEnumerator(); // 获取 int[] 的迭代器
- while(enumerator.MoveNext()) // 当前集合是否有下一个元素?
- {
- Console.WriteLine(enumerator.Current); // 获取当前元素
- }
- // 在这里,迭代器指向集合的末尾(类似C++的 arr.(c)end())
- }
- }
- }
复制代码 编译运行结果:- using System.Collections.Generic;
- using System.Collections;
- using System;
- namespace ForeachSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // C# 中的迭代器
- int[] intArr = { 1, 2, 3, 4, 5 };
- for(IEnumerator enumerator = intArr.GetEnumerator(); enumerator.MoveNext();)
- {
- Console.WriteLine(enumerator.Current);
- }
- // 在这里,迭代器指向集合的末尾(类似C++的 arr.(c)end())
- // enumerator.Reset();
- }
- }
- }
复制代码 输出参数
在声明的时候使用 out 修饰的参数,即为输出参数。当希望一个方法一次运行,就产生多个输出结果,就可以使用 out 关键字。
带有 out 关键字的方法一定是有副作用,可以用来获得了除了返回值之外的额外输出。
示例代码:- using System.Collections.Generic;
- using System.Collections;
- using System;
- namespace ForeachSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // C# 中的迭代器
- int[] intArr = { 1, 2, 3, 4, 5 };
- foreach(var ele in intArr)
- {
- Console.WriteLine(ele);
- }
- }
- }
- }
复制代码 TryParse 方法是不会抛出异常的,只会返回一个布尔值类型的状态。
注意:
- 输出参数并不创建变量的副本
- 方法体内必须有对输出参数赋值的操作
- 使用 out 修饰符显式指出 -- 此方法的副作用是通过参数向外输出值
- 从语义上来讲 -- ref 是为了改变,out 是为了输出
- 引用类型
示例代码:创建一个产出 Student 对象的工厂类,里面有一个 Create 方法- namespace OutParamSample{ internal class Program { static void Main(string[] args) { // 引用类型 Student stu = null; bool ok = StudentFactory.Create("Yuzu", 20, out stu); if (!ok) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Create student instance failed!");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>return; } else {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Create instance success!");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine($"Name = {stu.Name} Age = {stu.Age}"); } } } class Student { public string Name { get; set; } public int Age { get; set; } } class StudentFactory { public static bool Create(string stuName, int stuAge, out Student result) { result = null; if (string.IsNullOrEmpty(stuName)) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>return namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- }; } if (stuAge = 85) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>return namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- }; } result = new Student() { Name = stuName, Age = stuAge }; return true; } }}
复制代码 编译运行结果:- namespace BrushSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Brush br = new Brush();
- Console.WriteLine(Brush.DefaultColor.Red);
- Console.WriteLine(Brush.DefaultColor.Green);
- Console.WriteLine(Brush.DefaultColor.Blue);
- //Brush.DefaultColor.Blue = 255; // CS1650
- }
- }
- struct Color
- {
- public int Red;
- public int Green;
- public int Blue;
- }
- class Brush
- {
- public static readonly Color DefaultColor;
- static Brush() // 静态构造器
- {
- Brush.DefaultColor = new Color() { Red = 0, Green = 0, Blue = 0 }; // 也可以写在25行后
- }
- }
- }
复制代码注意事项同值类型
数组参数
必须是形参列表中的最后一个,由 params 修饰,一个方法中最多只能有一个 params 参数
举例:String.Format 和 String.Split 方法
示例代码:- namespace ParamSample{ // 数组参数params 示例 internal class Program { static void Main(string[] args) { // 必须先声明一个数组 double[] arr1 = new double[] { 1.1, 3.14, 6.18 }; Console.WriteLine(SumArr(arr1)); // 以 params 的形式输入参数:不再需要提前声明数组,编译器会根据给出的值自动创建数组 double res2 = SumArr(1.1, 2.2, 3.14, 6.18); Console.WriteLine(res2); // 其他示例 int x = 1; int y = 2; int z = x + y; Console.WriteLine("{0} + {1} = {2}", x, y, z); //split string hamlet = "to,be.or;not.to,be"; string[] hamletSplited = hamlet.Split(',','.',';', ' '); if(hamlet.Length != 0) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>foreach(var ele in hamletSplited)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Console.WriteLine(ele);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } } public static double SumArr(params double[] arr) { double res = 0; for (int i = 0; i < arr.Length; i++) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>res += arr[i]; } return res; } }}
复制代码 编译运行结果:- namespace PropertySample1
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student(12, "Yuzu");
- Console.WriteLine(s1.Age);
- s1.Age = 32;
- }
- }
- class Student
- {
- private int age;
- public int Age
- {
- set
- {
- if (value >= 0 && value <= 130)
- {
- this.age = value;
- }
- else
- {
- throw new Exception("Input Wrong Age");
- }
- }
- get { return age; }
- }
- public string Name;
- public Student(int _age, string _Name)
- {
- this.Age = _age;
- this.Name = _Name;
- }
- }
- }
复制代码 具名参数
剧名参数即我们在调用的时候可以指定参数的名称,这样代码的可读性会更佳。
下面是一个简单的示例- private static int age;
- public static int Age
- {
- set
- {
- if( value >= 0 && value <= 130)
- {
- age = value;
- }
- else
- {
- throw new Exception("Input age number error!")
- }
- }
- get { return age; }
- }
复制代码 在第 11 行,我们指定了变量名称,这样具有了更佳的可读性,而且比起不具名参数,具名参数在传值时可以调换顺序。
可选参数
即带有默认值的参数,不建议使用,和 C++ 中的写法类似。
扩展方法(this 参数)
- 方法必须是公有的、静态的、即被 public static 所修饰
- 必须是形参列表中的第一个,由 this 修饰
- 必须由一个静态类(一般类名为 SomeTypeExtension )来统一收纳对 SomeType 类型的拓展方法
举例:LINQ 方法- namespace PropertySample2
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- try
- {
- Student s = new Student(12, "Yuzu");
- s.Age = 140;
- Console.WriteLine($"Name: {s.Name}, Age: {s.Age}");
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- }
- class Student
- {
- public int Age { set; get; } // 简略的属性(包装器)写法,不会抛出任何异常
- public string Name;
- public Student(int _Age, string _Name)
- {
- Age = _Age;
- Name = _Name;
- }
- }
- }
复制代码 编译运行结果:- class Student
- {
- public string Name { private get => name; set => name = value; }
- private string name;
- }
复制代码 在调用的时候,只需要输入一个参数(第一个参数为 this)。
Linq 示例:- namespace PropertySample2
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- try
- {
- Student s = new Student(12, "Yuzu");
- Console.WriteLine("{1} Can Work: {0}", s.CanWork, s.Name);
- Student s1 = new Student(22, "Akita");
- Console.WriteLine("{1} Can Work: {0}", s1.CanWork, s1.Name);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- }
- class Student
- {
- public int Age { get; set; } // 简略的属性(包装器)写法,不会抛出任何异常
- public string Name;
- public Student(int _Age, string _Name)
- {
- Age = _Age;
- Name = _Name;
- }
- // 根据输入值动态
- public bool CanWork
- {
- get
- {
- if (Age >= 16)
- {
- return true;
- }
- else
- {
- return namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };
- }
- }
- }
- }
- }
复制代码 上述代码的第 14 行 bool result = lst.All(e => e > 10); 中的 All 方法就为一个扩展方法。
编译运行结果:源码中 All 的定义:- public int? this[string subject]
- {
- get
- {
- // ...
- }
- set
- {
- // ...
- }
- }
复制代码 返回值:如果 source 中的每个元素都通过了指定谓词(predicate)中的测试逻辑,或者序列为空,则为 true;否则为 namespace IndexerSample
{
internal class Program
{
static void Main(string[] args)
{
Student s1 = new Student("math", 60);
var mathScore = s1["math"];
Console.WriteLine(mathScore);
s1["English"] = 95;
s1["Physics"] = 80;
Console.WriteLine(s1["Physics"]);
}
}
class Student
{
public Student(string key, int val)
{
scoreDict[key] = val;
}
private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
public int? this[string subject] // this 为可空类型
{
get
{
if (scoreDict.ContainsKey(subject))
{
return scoreDict[subject];
}
else
{
return null;
}
}
set
{
if (!value.HasValue)
{
throw new Exception("Score cannot be null");
}
else
{
if (scoreDict.ContainsKey(subject))
{
namespace ParameterSample
{
internal class Program
{
static void Main(string[] args)
{
Student s2 = new Student() { Name = "Mio" };
UpdateObject(s2);
Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
}
public static void UpdateObject(Student s)
{
s.Name = "Kamigami"; // 避免修改值,较为少用
Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
}
}
class Student
{
public string Name { get; set; }
}
}scoreDict[subject] = value.Value;
}
else
{
namespace ParameterSample
{
internal class Program
{
static void Main(string[] args)
{
Student s2 = new Student() { Name = "Mio" };
UpdateObject(s2);
Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
}
public static void UpdateObject(Student s)
{
s.Name = "Kamigami"; // 避免修改值,较为少用
Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
}
}
class Student
{
public string Name { get; set; }
}
}scoreDict.Add(subject, value.Value);
}
}
}
}
}
}。
使用场景:
- 传值参数:参数的默认传递方式
- 输出参数:用于除返回值外还需要输出的场景
- 引用参数:用于需要修改实际参数的场景
- 数组参数:用于简化方法的调用
- 具名参数:提高可读性
- 可选参数:参数拥有默认值
- 扩展方法( this 参数):为目标数据类型 “追加” 方法
2.8 委托与事件
2.8.1 委托
什么是委托?
简单来说,委托就是函数指针的 “升级版”,是更加安全的函数指针。也可以说委托封装了方法。
下面是 C/C++ 中函数指针的示例:- #include int add(int a, int b){ int result = a + b; return result;}int sub(int a, int b){ int result = a - b; return result;}int main(){ int x = 42; int y = 40; // 常规调用 std::cout {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.textBox1.Text = "Use lambda"; }; } // 一个事件处理器 ButtonClicked 可挂接多个事件:三个按钮的点击事件 private void ButtonClicked(object sender, EventArgs e) { if (sender == this.button1) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.textBox1.Text = "button1 clicked!"; } if (sender == this.button2) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.textBox1.Text = "button2 clicked!"; } if (sender == this.button3) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.textBox1.Text = "use named delegate"; } } }}
复制代码 在这段代码中可以看到,能够使用多种机制实现事件和事件处理器的挂接,常见的如以下四种(按照使用率和推荐程度由上到下排列):
- 使用方法直接充当事件处理器,如上面代码,可以这样挂接事件处理器和事件:
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student() { Name = "Yuzu" };
- SomeMethod(s1);
- Console.WriteLine(s1.Name);
- Console.WriteLine($"{s1.GetHashCode()}: {s1.Name}");
- }
- public static void SomeMethod(Student stu)
- {
- stu = new Student() { Name = "Ayaka" }; // 丢弃掉原有对象,重新创建对象(少见)
- Console.WriteLine(stu.Name);
- Console.WriteLine($"{stu.GetHashCode()}: {stu.Name}");
- }
-
- }
- class Student
- {
- public string Name { get; set; }
- }
- }
复制代码 - 使用委托充当事件处理器(此时委托需要与编写好的事件处理方法遵循相同的约束条件)
- Ayaka
- 27252167: Ayaka
- Yuzu
- 43942917: Yuzu
复制代码 这里的 EventHandler 参数和 ButtonClicked 参数类型都相同,就和使用普通的委托没有区别
- 使用匿名函数充当事件处理器,这种方法可以实现类型推导,个人建议不要省略参数,不利于代码阅读和代码调试
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student() { Name = "Yuzu" };
- SomeMethod(s1);
- Console.WriteLine(s1.Name);
- Console.WriteLine($"{s1.GetHashCode()}: {s1.Name}");
- }
- public static void SomeMethod(Student s1)
- {
- s1 = new Student() { Name = "Yuzu" }; // 丢弃掉原有对象,重新创建对象(少见)
- Console.WriteLine(s1.Name);
- Console.WriteLine($"{s1.GetHashCode()}: {s1.Name}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }
复制代码 - (不推荐)使用匿名委托充当事件处理器,这种方法可以被匿名函数替代
- Yuzu
- 27252167: Yuzu
- Yuzu
- 43942917: Yuzu
复制代码
注意:
- 一个事件处理器可以挂接多个事件(一个事件处理器 ButtonClicked 挂接了三个按钮的 Click 事件)
- 一个事件也可以被多个事件处理器挂接(如先前示例中 Timer 的 Elaped 事件,挂接了两个事件处理器:girl.Action 和 boy.Action)
WPF 应用示例
这里使用 .net framework 4.8,.net core 下的WPF的API可能与前者的有所区别。
在WPF中拖控件,如往面板中添加 TextBox 和 Button,会看到如下的锁链标记:
该标记可以通过点击更改状态,默认为,即打开状态,该状态下如果对窗体边缘进行拖拽,对应的控件不会随之改变大小。点击后变为,此状态下,拖动窗体边缘,对应控件会随着窗体改变。该图标一般有左右两个
界面
MainWindow.xaml- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>
复制代码 xaml 中挂接事件和事件处理器写法和 C# 中不一样,XAML 中为:- [/code][b]XAML 中可以挂载事件处理器给事件[/b]。最后面的 Click="ButtonClicked" 就是事件和事件处理器的挂接方式。
- MainWindow.xaml.cs
- [code]namespace RefSideEffect
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- int num = 42;
- UseSideEffect(ref num); //
- Console.WriteLine($"Num = {num}");
- }
- public static void UseSideEffect(ref int input) // 声明
- {
- input += 3;
- Console.WriteLine($"Num = {input}");
- }
- }
- }
复制代码 如果不在 XAML 中挂载事件和事件处理器,也可以直接在 C# 中使用先前的方式(传统的方式)进行事件处理:
变更后的MainWindow.xaml- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>
复制代码 删除了第 11 行的代码:Click="ButtonClicked",在 MainWindow.xaml.cs 中添加代码:this.button1.Click += ButtonClicked
变更后的MainWindow.xaml.cs- Name = Ayaka, HashCode = 27252167
- ====================================
- Name = Yuzu, HashCode = 43942917
- Name = Yuzu, HashCode = 43942917
复制代码 RoutedEventHandler 和 ButtonClicked 的约束条件相同,即参数类型都为 (object, RoutedEventArgs) 类型。
事件的声明
完整声明
我们声明一个 Waiter 类作为事件接收者,一个 Customer 类作为事件拥有者。Customer 经过一连串的动作,向 Waiter 发起点餐操作,而 Waiter 响应 Customer 的点餐操作,完成服务。
下面的声明该这么写:编写思路如下:
- 声明事件处理器的委托
事件是基于委托的:事件这种成员,无论是从表层约束来讲,还是底层实现来讲,都是依赖于委托类型的。
此外,应当注意:不要将事件处理器声明写到类中,否则这个类就成了一个嵌套类型,在这里委托并不是类的一个字段- Name = Azaka, HashCode = 2606490
- =============================
- Name = Tom, HashCode = 2606490
- Name = Tom, HashCode = 2606490
复制代码声明委托类型:写在和类平级的地方。使用 EventHandeler 作为事件处理器后缀的原因:
- 委托类型是为了声明 Order 事件使用的
- 使用 EventHandler 后缀,表明该委托是为了约束事件处理器的
- 这个委托创建的实例,未来是为了存储事件处理器的
- 声明事件参数 OrderEventArgs ,要继承 EventArgs 类,XxxEventArgs 中的 Xxx 是我们的事件名称。
- namespace OutParamSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Please input a number: ");
- string arg1 = Console.ReadLine();
- double db1 = 0.0;
- bool success = double.TryParse(arg1, out db1);
- if (!success) { Console.WriteLine("Input error!"); }
- else { Console.WriteLine(db1); }
- }
- }
- }
复制代码 - 编写事件拥有者的事件以及触发方法。
第一:声明事件 Order ,以及触发该事件的方法 Trigger;
第二:声明一个委托实例,如 private OrderEventHandler orderEventHandler;
第三:使用一个包装器对该私有字段进行封装,这里的 Order 就是该委托实例 orderEventHandler 的包装,供外界访问。该包装返回类型被封装的事件类型,返回值要用 event 进行修饰(如:event OrderEventHandler)
第四,触发方法中需要创建相关事件参数 EventArgs 实例,再使用事件处理器委托类型实例的 Invoke 方法(如下第 41 行代码)传递参数
在使用该事件的时候,要和对应的事件处理器进行挂接- // 事件的拥有者public class Customer{ private OrderEventHandler orderEventHandler; public event OrderEventHandler Order // 包装事件处理器 { // 事件处理器的添加器 add { this.orderEventHandler += value; } // 事件处理器的删除器 remove { this.orderEventHandler -= value; } } public double Bill { get; set; } public void PayTheBill() { Console.WriteLine($"I will pay ${this.Bill}"); } // 以下有简写部分 public void WalkIn(){/*Expression(s)*/} public void SitDown(){/*Expression(s)*/} public void Think() { for(int i = 0; i < 5; ++i) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Let me think!");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Thread.Sleep(1000); }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> if(this.orderEventHandler != null) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>OrderEventArgs e = new OrderEventArgs();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.DishName = "KFC Chicken Wings";<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.Size = "large";<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.orderEventHandler.Invoke(this, e); } } // 事件触发的方法 public void Trigger() { Console.ReadLine(); this.WalkIn(); this.SitDown(); this.Think(); }}
复制代码 - 编写事件响应者和实现事件处理器。事件处理器应当遵循第一步声明委托的参数约束条件。一般以 XxxAction 作为名称
- Create instance success!
- Name = Yuzu Age = 20
复制代码 简略声明
字段式声明(field-like):只是看起来像是字段,本身是一个语法糖。但是事件本身不是类的字段,使用简略声明:- using System;using System.Timers;namespace EventSample{ class Program { static void Main() { // ... } } Name = Azaka, HashCode = 2606490
- =============================
- Name = Tom, HashCode = 2606490
- Name = Tom, HashCode = 2606490 public class Waiter { public void Action(Customer customer, OrderEventArgs e) { // ... } } public class OrderEventArgs: EventArgs { // ... } // 事件拥有者 public class Customer { public static double Bill{get; set;} public event OrderEventHandler Order; // 事件的简略声明,不是字段! // ...<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>public void Think() { //...<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> if(this.Order != null) // 修改后 {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>OrderEventArgs e = new OrderEventArgs();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.DishName = "KFC Chicken Wings";<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.Size = "large";<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Order.Invoke(this, e); // 修改后 } } // ... }}
复制代码 从完整声明换成简略声明,会有破坏性的更改(有好有坏),这个特性使用的时候要注意,需要将后续对事件的变量名全部进行修改。
查看我们生成的可执行文件(或者dll文件),如下:
- 水蓝色方块:字段
- 紫色方块:方法
- 绿色倒三角:事件
可以看到事件 Order 有一个对应的同名字段,这是在使用简略事件声明之后,编译器自己生成的。
委托和事件的区别
有了委托字段/属性,为什么还需要事件?
回答:为了保证程序安全,防止功能被乱用。事件本质上是委托的一层包装,封闭了绝大多委托自带的方法,下面是《C#图解教程》中的示意图:
使用事件作为字段可能会导致一些问题,主要有以下几点:
- 直接访问事件可能导致不安全的调用:
在 Customer 类中,事件 Order 被当作字段使用,可以直接访问。这样的设计可能导致外部代码直接触发事件,而不经过类的封装和控制。这违反了封装的原则,使得外部代码可以绕过类的逻辑进行事件的触发,可能导致不可预料的行为。
- 事件丧失了事件的本质:
事件是一种特殊的委托,它提供了一种更安全、更封装的方式来处理发布-订阅模型。将事件当作字段使用,丧失了事件的封装性,失去了事件的特有优势,如添加和移除事件处理程序的安全性。
- 无法防止外部代码直接赋值:
如果事件被当作字段使用,外部代码可以直接将新的委托赋值给事件,而不经过事件的 add 和 remove 操作。这可能导致未经检查的事件处理程序,而无法进行必要的验证和控制。
修复这些问题的方法是将事件声明为标准的事件,使用 event 关键字。这样可以确保事件的封装性和安全性,同时提供了更好的控制机制。在先前的代码修复中,已经将 Customer 类中的 Order 事件声明改正为标准的事件。
可以给他人私自点菜的代码编译运行结果:- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // 具名参数
- string personName = "Yuzu";
- int personAge = 99;
- PrintInfo(Name: personName, Age: personAge);
- }
- static void PrintInfo(string Name, int Age)
- {
- Console.WriteLine($"Name : {Name}, Age : {Age}");
- }
- }
- }
复制代码 此时顾客本来只点了一份食物,而别人替他点另外两份,那么他就要付三份食物的钱,这是一种让人原地飞升的操作。
事件的本质
事件的本质是委托字段的一个包装器
- 这个包装器对委托字段的访问起限制作用,相当于一个“蒙版”
- 封装(encapsulation)的一个重要功能就是隐藏
- 事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
- 添加/移除事件处理器的时候可以直接使用方法名,这是委托实例所不具备的功能
用于声明事件的委托类型的命名规定
- 用于声明 Foo 事件的委托,一般命名为 FooEventHandler(除非是一个非常通用的事件约束)
- FooEventHandler 委托的参数一般有两个(由 Win32 API演化而来,历史悠久)
直接使用 EventHandler 委托,可以省略委托类型的声明,此时代码会变成这样,此时需要进行类型转换,如第 12 到 13 行代码所示:
- 第一个是 object 类型,名字为 sender,实际上就是事件的拥有者、事件的 source
- 第二个是 EventArgs 类的派生类,类名一般为 FooEventHandler,参数名为 e。也就是前面讲过的事件参数
- 虽然没有官方的说法,但我们可以把委托的参数列表看作是事件发生后发送给事件响应者的“事件消息”
- 触发 Foo 事件的方法一般命名为 OnFoo,即“因何引发”、“事出有因”
- 访问级别为 protected,不能为 public,不然又成了可以“借刀杀人”了
将 Customer 的触发方法重写:- using System;using System.Threading;namespace EventDeclareSample{ // ... public class Customer { // ... public void Think() { for (int i = 0; i < 5; ++i) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine("Let me think...");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Thread.Sleep(1000); } this.OnOrder("KFC Chicken Wings", "large"); // 调用事件的触发方法 } public void Trigger() { // ... } // 事件的方法名:OnOrder protected void OnOrder(string dishName, string size) { // 一定要判断事件封装的委托是否为空 if (this.Order != null) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>OrderEventArgs e = new OrderEventArgs();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.DishName = dishName;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>e.Size = size;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this.Order.Invoke(this, e); // 事件必须要求事件拥有者触发,所以在这里传递 this } } } public class OrderEventArgs : EventArgs { // ... } public class Waiter { public void Action(object sender, EventArgs e) { // ... } }}
复制代码
事件的命名约定
- 带有时态的动词或者动词短语
- 事件拥有者“正在做”什么事情,用进行时;事件拥有者“做完了”什么事情,用完成时
事件与委托的关系
事件是“以特殊方式声明的委托字段/实例”吗?
- 不是!只是声明的时候“看起来像”(对比委托字段与事件的简化声明,field-like)
- 事件声明的时候使用了委托类型,简化声明造成事件看上去像是一个委托的字段(实例),而 event 关键字则更像一个修饰符 —— 这是错觉的来源之一
- 订阅事件的时候 += 操作符后面可以是一个委托实例,这与委托实例的赋值方法语法相同,这也让事件看起来更像是一个委托字段 —— 这是错觉的又一来源
- 重申:事件的本质是加装在委托字段上的一个“蒙版”(Mask),是个起掩蔽作用的包装器。这个用于阻挡非法操作的“蒙版”绝不是委托字段本身
为什么要使用委托类型来声明事件?
- 站在 source 的角度看,是为了表明 source 能对外传递哪些消息
- 站在 subscriber 角度来看,它像是一种约定,是为了约束能够使用什么样签名的方法来处理(响应)事件
- 委托类型的实例将用于存储(引用)事件处理器
对比事件与属性
- 属性不是字段 —— 很多时候属性是字段的包装器,这个包装器用来保护字段不被滥用
- 事件不是委托字段 —— 它是委托字段的包装器,这个包装器用来保护委托字段不被滥用
- 包装器永远不可能是被包装的东西
2.9 OOP 详解
在两章之前学习了面向对象编程初步的知识,这一章来详解 C# 中的 OOP 编程范式
什么是类?
- 是一种数据结构
- 是一种数据类型
- 代表现实世界中的“种类”
2.9.1 两种构造器
C# 中构造器有两种:实例构造器和静态构造器
使用多种方式创建类型实例:
- 直接调用实例构造器
- 使用反射,这种方式充分展示了类的类型一面
- 使用 dynamic 关键字
示例:编写一个 Student 类,将它的代码写在单独的一个文件种
Student.cs- using System;namespace HelloClass{ class Student { public static int Amount { get; private set; } public string Name { get; set; } public int ID { get; set; }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>// 创建自己的实例构造器:看起来像一个方法,但是没有返回值。快捷键:ctor + Enter public Student(string name, int id) { this.Name = name; this.ID = id; Amount++; }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>// 实例析构器 ~Student() { Amount--; Console.WriteLine("Bye, Releasing System Resources ..."); }<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>// 静态构造器:只能构造静态成员 static Student() { Amount = 0; } public void Report() { Console.WriteLine($"I'm No.{this.ID} student, my name is {this.Name}"); } }}
复制代码 Program.cs- using System;namespace HelloClass{ internal class Program { public static void Main(string[] args) { // 1.使用实例构造器创建对象 Student stu1; // 声明变量 // stu1 = new Student() { Name = "Yuzu", ID = 12 }; // 创建实例,调用默认构造器 stu1 = new Student("Yuzu", 12); // 使用自建实例构造器,stu1 为 Student 类的实例 Console.WriteLine(stu1.Name); // Yuzu Console.WriteLine(stu1.ID); // 12 stu1.Report();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 2.使用反射创建实例:充分展现类的类型一面 Type t = typeof(Student); // 拿到类型信息 // 使用类型信息创建实例 o, CreateInstance 创建的实例都为 object 类型 object o = Activator.CreateInstance(t, "Aoko", 1); // 此时 o 类型已经丢失了很多信息,但是它的类型名字还是 Student,说明可以找回来 Console.WriteLine(o.GetType().Name); // Student // 转换为 Student 类型 Student s = o as Student; s?.Report();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 3.使用 dynamic 创建实例 Type t1 = typeof(Student); dynamic stu2 = Activator.CreateInstance(t1, "Shizuku", 18); Console.WriteLine(stu2.Name); // Shizuku Console.WriteLine(Student.Amount); // 3 } }}
复制代码 代码编译运行结果:- public static bool All<TSource>(
- this IEnumerable<TSource> source,
- Func<TSource, bool> predicate
- )
复制代码 使用第三种方式创建类型的实例,可能遇到如下错误:- #include <iostream>
- int add(int a, int b)
- {
- int result = a + b;
- return result;
- }
- int sub(int a, int b)
- {
- int result = a - b;
- return result;
- }
- int main()
- {
- int x = 42;
- int y = 40;
- // 常规调用
- std::cout << add(x, y) << '\n';
- std::cout << sub(x, y) << '\n';
- // 函数指针: C++11 用法
- using funcPtr = int (*)(int, int); // 声明指针类型:函数指针,接收两个int参数,返回一个int类型值
- funcPtr calcPtr = add; // 创建指针类型变量
- auto result = calcPtr(x, y); // 调用函数指针变量
- calcPtr = sub;
- auto result1 = calcPtr(x, y);
- std::cout << result << '\n';
- std::cout << result1 << '\n';
- // C 类型函数指针
- typedef int (*FunctionPtr)(int, int); // 声明指针类型,作用同上
- FunctionPtr calcPointer = add;
- int r1 = calcPointer(x, y);
- calcPointer = sub;
- int r2 = calcPointer(x, y);
- printf("%d\n", r1);
- printf("%d\n", r2);
- return 0;
- }
复制代码 此时需要使用 nuget 安装包:Microsoft.CSharp 版本为 v4.8,安装了基本就能解决这个问题
实例构造器
上述代码中,实例构造器如下,如果自定义了实例构造器,那么默认的实例构造器就会失效,要按照我们约定的构造器传入参数进行实例构造。- namespace DelegateSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // C# 中预定义了很多委托类型供使用
- Calculator cal = new Calculator();
- // 1. Action 委托类型:绑定没有返回值、没有形参的方法
- Action? ac = new Action(cal.Report);
- ac(); // 使用委托变量调用 cal 的 Report 方法,这种写法为模仿函数指针的书写方式
- // ac = null; // 清空委托
- ac += cal.SayHi; // 将方法(或委托)添加到调用列表中
- ac.Invoke();
- }
- }
- class Calculator
- {
- public void Report()
- {
- Console.WriteLine("I have 3 methods.");
- }
- public void SayHi()
- {
- Console.WriteLine("Hello Test!");
- }
- }
- }
复制代码 此外还有实例析构器- I have 3 methods.
- I have 3 methods.
- Hello Test!
复制代码 静态构造器
静态构造器只能用来初始化静态成员,无法构造实例成员。
这里的静态成员只有 Amount(public static int Amount { get; private set; })- namespace DelegateSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- // C# 中预定义了很多委托类型供使用
- Calculator cal = new Calculator();
- // 2. Func 委托类型:绑定有参数、有返回值的方法
- int x = 42;
- int y = 40;
- int res = 0;
- Func<int, int, int> func = new Func<int, int, int>(cal.Add); // <> 最后一个参数为返回值类型,前面的为形参类型
- res = func.Invoke(x, y);
- Console.WriteLine(res); // 82
- func = new Func<int, int, int>(cal.Sub);
- res = func.Invoke(x, y);
- Console.WriteLine(res); // 2
- }
- }
- class Calculator
- {
- public int Add(int x, int y)
- {
- return x + y;
- }
- public int Sub(int x, int y)
- {
- return x - y;
- }
- }
- }
复制代码 2.9.2 类的声明、继承与控制
类声明的位置
类可以声明在名称空间内、其他类中(作为成员类)、或者声明在所有显式名称空间之外在C++中,类的声明和定义是分离的,而在 C# 和Java 中,类的声明和定义和合并在一起的。
C++ 中类的定义示例:
Student.h- namespace DelegateSample1
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Type t = typeof(Func<>);
- Console.WriteLine(t.IsClass);
- Type t2 = typeof(Action);
- Console.WriteLine(t2.IsClass);
- }
- }
- }
复制代码 Student.cppprotected(受保护的):
- protected 访问限定符允许 class 在包含它的类或结构体以及派生类中可见。
- 这表示除了包含该类的类或结构体之外,任何继承自这个类的类也能访问它。
- namespace DelegateSample1
- {
- delegate double Calc(double a, double b); // Calculator 中方法的委托
- internal class Program
- {
- static void Main(string[] args)
- {
- Calculator calculator = new Calculator();
- Calc addCalc = new Calc(calculator.Add);
- Calc subCalc = new Calc(calculator.Sub);
- Calc divCalc = new Calc(calculator.Div);
- Calc mulCalc = new Calc(calculator.Mul);
- double x = 3.15;
- double y = 6.18;
- var res1 = addCalc(x, y);
- var res2 = subCalc(x, y);
- var res3 = divCalc(x, y);
- var res4 = mulCalc(x, y);
- Console.WriteLine("{0:f4}, {1:f4}, {2:f4}, {3:f4}", res1, res2, res3, res4);
- }
- }
- class Calculator
- {
- public double Add(double x, double y)
- {
- return x + y;
- }
- public double Sub(double x, double y)
- {
- return x - y;
- }
- public double Div(double x, double y)
- {
- return x / y;
- }
- public double Mul(double x, double y)
- {
- return x * y;
- }
- }
- }
复制代码 internal(内部的):
- internal 访问限定符允许 class 在包含它的程序集中的任何地方可见。
- 这意味着只有在同一程序集中的代码可以直接访问该类,而在其他程序集中则无法访问。
- 9.3300, -3.0300, 0.5097, 19.4670
复制代码 public(公共的):
- public 访问限定符使得 class 对所有类可见,不论是否在同一程序集中。
- 这允许在任何地方都能够直接访问该类。
- namespace DelegateSample2
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- //世界上出现了一个生产产品的工厂(创建产品生产工厂实例)
- ProductFactory productFactory = new ProductFactory();
-
- //世界上出现了一个包装产品的工厂(创建包装产品工厂实例)
- WrapFactory wrapFactory = new WrapFactory();
- //产品工厂找到了包装厂让他给进行包装产品的订单(两个订单:ToyCar和Pizza)(创建委托实例)
- Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
- Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);
-
- //包装厂进行订单处理,对生产产品的工厂下的订单进行产品包装(获取包装好的产品)
- Box box1 = wrapFactory.WrapProduct(func1);
- Box box2 = wrapFactory.WrapProduct(func2);
- //生产产品的厂子对包装厂包装的产品进行查验
- Console.WriteLine(box1.Product.Name);
- Console.WriteLine(box2.Product.Name);
- }
- }
- class Product
- {
- public string Name { get; set; }
- }
- class Box
- {
- public Product Product { get; set; }
- }
- class WrapFactory
- {
- public Box WrapProduct(Func<Product> getProduct)
- {
- Box box = new Box();
- Product product = getProduct.Invoke();
- box.Product = product;
- return box;
- }
- }
- class ProductFactory
- {
- public Product MakePizza()
- {
- Product product = new Product();
- product.Name = "Pizza";
- return product;
- }
- public Product MakeToyCar()
- {
- Product product = new Product();
- product.Name = "Toy Car";
- return product;
- }
- }
- }
复制代码 总体来说,private 提供了最高的封装性,只允许包含它的类直接访问。protected 允许派生类访问,internal 允许在同一程序集中的任何地方访问,而 public 允许在任何地方都能访问。选择适当的访问限定符取决于你的设计需求,确保对类的可见性进行适当的控制,以保持良好的封装性和代码安全性。
类的继承
C# 中所有类都是单根的,意思就是,所有类的继承链的顶端都是 Object,示例:- using System;namespace HelloOOP{ internal class Program { public static void Main(string[] args) { // 获取Car的类型和Car的基类 Type t = typeof(Car); Type baseType = t.BaseType; string baseTypeName = baseType.FullName; // HelloOOP.Vehicle Console.WriteLine(baseTypeName);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 获取Car的基类的基类 Type objectType = baseType.BaseType; Console.WriteLine(objectType.FullName); // System.Object<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 获取Car的基类的基类的基类 Type nullType = objectType.BaseType; Console.WriteLine(nullType); Console.WriteLine(nullType == null); // True } } class Vehicle { } class Car : Vehicle { }}
复制代码 编译运行结果:- namespace DelegateSample2
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- //世界上出现了一个生产产品的工厂(创建产品生产工厂实例)
- ProductFactory productFactory = new ProductFactory();
-
- //世界上出现了一个包装产品的工厂(创建包装产品工厂实例)
- WrapFactory wrapFactory = new WrapFactory();
- //产品工厂找到了包装厂让他给进行包装产品的订单(两个订单:ToyCar和Pizza)(创建委托实例)
- Func<Product> func1 = new Func<Product>(productFactory.MakePizza);
- Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);
- // 声明Logger类实例
- Logger logger = new Logger();
- Action<Product> log = new Action<Product>(logger.Log);
-
- //包装厂进行订单处理,对生产产品的工厂下的订单进行产品包装(获取包装好的产品)
- Box box1 = wrapFactory.WrapProduct(func1, log); // log 为回调方法
- Box box2 = wrapFactory.WrapProduct(func2, log);
- //生产产品的厂子对包装厂包装的产品进行查验
- Console.WriteLine(box1.Product.Name);
- Console.WriteLine(box2.Product.Name);
- }
- }
- class Logger
- {
- public void Log(Product product) {
- Console.WriteLine("Product '{0}' created at {1}. Price is {2}", product.Name, DateTime.UtcNow, product.Price);
- }
- }
- class Product
- {
- public string Name { get; set; }
- public double Price { get; set; }
- }
- class Box
- {
- public Product Product { get; set; }
- }
- class WrapFactory
- {
- public Box WrapProduct(Func<Product> getProduct, Action<Product> logCallback)
- {
- Box box = new Box();
- Product product = getProduct.Invoke();
- // 产品价格大于50块,log记录一次
- if (product.Price > 50)
- {
- logCallback(product);
- }
- box.Product = product;
- return box;
- }
- }
- class ProductFactory
- {
- public Product MakePizza()
- {
- Product product = new Product();
- product.Name = "Pizza";
- product.Price = 40;
- return product;
- }
- public Product MakeToyCar()
- {
- Product product = new Product();
- product.Name = "Toy Car";
- product.Price = 60;
- return product;
- }
- }
- }
复制代码 在声明 Vehicle 类时,没有注明继承类型,实际上继承了 Object,可以这么写(一般不这么写):- Product 'Toy Car' created at 2023-12-30 9:36:07. Price is 60
- Pizza
- Toy Car
复制代码注意:
需要明确的概念:是一个(英语译作 is a),即 A 是一个 B,在面向对象编程中,一个子类的实例,同时也 是一个 父类的实例。
如:汽车是一个交通工具;一个老师是一个人;一个学生是一个人。
反之,交通工具不一定是汽车,人也不一定是老师,这类在C#中统统判定为 False
使用代码进行验证:- using System;namespace HelloOOP{ internal class Program { public static void Main(string[] args) { Car car = new Car(); Console.WriteLine(car is Vehicle); // True,一辆汽车是一个交通工具 Console.WriteLine(car is Object); // True,一辆汽车是一个Object(物件)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> Vehicle vehicle = new Vehicle(); Console.WriteLine(vehicle is Car); // False } } class Vehicle { } class Car : Vehicle { }}
复制代码 编译运行结果:- using System;
- using System.Threading;
- // .net framework 中需要
- namespace MultiCastSampleFramwork
- {
- // 多播委托
- internal class Program
- {
- static void Main(string[] args)
- {
- Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.DarkRed };
- Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.DarkBlue };
- Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.DarkCyan };
-
- // 一个委托封装一个方法:单播委托
- Action ac1 = stu1.DoHomeWork;
- Action ac2 = stu2.DoHomeWork;
- Action ac3 = stu3.DoHomeWork;
-
- // 隐式创建异步调用:新版 dotnet 不再支持
- ac1.BeginInvoke(null, null); // 创建一个分支线程调用封装的方法
- ac2.BeginInvoke(null, null);
- ac3.BeginInvoke(null, null);
- for (int i = 0; i < 10; ++i)
- {
- Console.ForegroundColor = ConsoleColor.Cyan;
- Console.WriteLine("Main thread {0} ", i);
- Thread.Sleep(1000);
- }
- }
- }
- class Student
- {
- public int ID { set; get; }
- public ConsoleColor PenColor { get; set; }
- public void DoHomeWork()
- {
- for (int i = 1; i <= 5; ++i)
- {
- Console.ForegroundColor = this.PenColor;
- Console.WriteLine($"Student {this.ID} doing homework {i} hour(s).");
- Thread.Sleep(1000); // 线程睡 1000ms
- }
- }
- }
- }
复制代码 可以使用父类类型的变量,引用子类类型的实例(因为一个子类的实例,同时也是一个父类的实例),示例:- using System;namespace HelloOOP{ internal class Program { public static void Main(string[] args) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 可用 父类变量 引用 子类实例 Object o1 = new Car(); Object o2 = new Vehicle();<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 错误,不可用子类变量引用父类实例 // Car c2 = new object(); // ERROR<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> // 将父类实例转回子类实例 Car c1 = o1 as Car; Vehicle v1 = o2 as Vehicle; Console.WriteLine(c1.GetType()); Console.WriteLine(v1.GetType()); } } class Vehicle { } class Car : Vehicle { }}
复制代码
- 类在功能上的扩展(extend)
- 只能有一个基类(即单继承),但可以实现多个其接口
- 类访问级别对继承的影响:子类的访问级别不能超越父类的访问级别,但是可以持平
- sealed 类不能被继承(类似 C++ 中的 final 限定符)
示例:- using System;
- using System.Timers;
- namespace EventSample1
- {
- using Timer = System.Timers.Timer; // 指定Timer,否则可能导致 ambiguous reference 错误
- internal class Program
- {
- public static void Main(string[] args)
- {
- Timer timer = new Timer(); // 事件拥有者timer,拥有Elapsed事件
- timer.Interval = 1000; // timer每1000ms触发一次Elapsed事件
- Boy boy = new Boy(); // 事件响应者:boy
- Girl girl = new Girl();
- timer.Elapsed += boy.Action; // 事件订阅:+=,左侧为事件,右侧为事件处理器
- timer.Elapsed += girl.Action;
- timer.Start();
- Console.ReadLine();
- }
- }
- class Boy
- {
- internal void Action(object sender, ElapsedEventArgs e)
- {
- Console.WriteLine("Jump!");
- }
- }
-
- class Girl{
- internal void Action(object sender, ElapsedEventArgs e)
- {
- Console.WriteLine("Sing!");
- }
- }
- }
复制代码 错误信息:Error CS0509 : “BMW”: 无法从密封类型“Car”派生
成员继承与访问
与 C++ 不同,C# 中的继承默认为公有的,不存在明确的私有继承概念。在C++中我们这么写一个类的继承:
car.hpp- using System;
- using System.Windows.Forms;
- namespace EventSample2
- {
- internal class Program
- {
- public static void Main(string[] args)
- {
- Form form = new Form();
- Controller controller = new Controller(form);
- form.ShowDialog();
- }
- }
- class Controller
- {
- private Form form;
- public Controller(Form mForm)
- {
- // 空对象无法返回事件,所以要先判断 form 是否为空
- if (mForm != null)
- {
- this.form = mForm;
- this.form.Click += (object sender, EventArgs e) =>
- {
- this.form.Text = DateTime.Now.ToString();
- };
- }
- }
- }
- }
复制代码 C++ 中,类的继承方式分为公有继承、私有继承和保护继承,默认为私有继承,在这里我们需要使用公有继承(public)
main.cpp- using System;
- using System.Windows.Forms;
- namespace EventSample3
- {
- internal class Program
- {
- public static void Main(string[] args)
- {
- MyForm form = new MyForm(); // 事件拥有者:form,事件响应者:form
- form.Click += form.FormClickedAction; // 事件处理器:FormClickedAction;挂接到事件:Click,即订阅
- form.ShowDialog();
- }
- }
- class MyForm : Form
- {
- internal void FormClickedAction(object sender, EventArgs e)
- {
- this.Text = DateTime.Now.ToString();
- }
- }
- }
复制代码 运行:- using System;
- using System.Windows.Forms;
- namespace EventSample4
- {
- internal class Program
- {
- public static void Main(string[] args)
- {
- MyForm form = new MyForm(); // 事件响应者:form
- form.ShowDialog();
- }
- }
- class MyForm : Form
- {
- private TextBox textBox;
- private Button button; // 事件拥有者:button
- public MyForm()
- {
- this.textBox = new TextBox();
- this.button = new Button();
-
- this.button.Text = "Say Baka!";
- this.button.Top = 30; // button 距离form上边沿的距离
-
- // 让这两个控件显示在当前form内
- this.Controls.Add(this.textBox);
- this.Controls.Add(this.button);
-
- // 挂接事件Click和事件处理器ButtonClickedAction
- this.button.Click += this.ButtonClickedAction;
- }
- internal void ButtonClickedAction(object sender, EventArgs e)
- {
- this.textBox.Text = "馬鹿馬鹿!";
- this.textBox.TextAlign = HorizontalAlignment.Center;
- }
- }
- }
复制代码 可以看到:Python 解释器本身在运行时并不会因为类型注解而改变其行为。类型注解通常在开发阶段被编辑器或类型检查工具使用,而在运行时被忽略。
2.9.4 partial 类
partial 类作用
C# 编译器允许我们将一个类拆分为两个或者多个部分进行编写,并且每个部分能以自己的节奏进行更新。而它们合起来还是同一个类。
partial 类的作用:减少类的派生,从而减少复杂度。
partial 类与 Entity Framework
使用 Entity Framework 查询数据表,这是生成的 datagram:
示例代码:
Program.cs- using System;namespace PartialClassSample1{ internal class Program { public static void Main(string[] args) { var dbContext = new AdventureWorksLT2012Entities(); var cts = dbContext.Address; foreach(var item in cts) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(item.PostalCode);<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>item.Report(); } } }}
复制代码 AddressPart2.cs- this.button3.Click += ButtonClicked; // ButtonClicked 已被实现
复制代码 使用 partial 类的特征,给 Address 类新增一个 Report 方法。
此时我在 Address 表单中新增一列:Price,允许设为 null 值:
然后要在 Visual Studio 中更新生成的 Datagram:
可以看到,最后一行已经可以看到我们新增的字段了。然后保存一下(这是必要的,因为此时会重新生成C#代码,否则没有这一列的自动提示字段)。
partial 类与 Windows Forms,WPF,ASP.Net Core
partial 类允许使用不同语言编写代码,如 WPF 中允许使用 XAML 语言设计UI界面,然后使用C#语言实现其逻辑。
2.10 接口和抽象类
接口和抽象类写的好,代码更加容易测试和维护。抽象类不可以实例化。
编写工程代码的 SOLID 原则:
SOLID 是一组设计原则,旨在帮助开发者创建更容易理解、灵活、可维护的软件系统。这些原则由罗伯特·C·马丁(Robert C. Martin)等人提出,每个原则代表了一种设计思想。下面是 SOLID 原则的简要介绍:
- 单一职责原则 (Single Responsibility Principle - SRP): 一个类应该只有一个引起变化的原因。换句话说,一个类应该只有一个职责。这有助于确保类在软件系统中的变化是可控的。
- 开放/封闭原则 (Open/Closed Principle - OCP): 软件实体(类、模块、函数等)应该对扩展是开放的,但对修改是封闭的。这意味着在不修改现有代码的情况下,可以通过添加新的代码来扩展系统的功能。
- 里氏替换原则 (Liskov Substitution Principle - LSP): 子类应该能够替换其基类而不影响程序的正确性。这意味着任何基类可以被其子类无缝替换,而程序行为不会受到影响。
- 接口隔离原则 (Interface Segregation Principle - ISP): 不应该强迫客户端依赖于它们不使用的接口。一个类不应该被迫实现它不使用的接口。这有助于避免不必要的依赖和复杂性。
- 依赖反转原则 (Dependency Inversion Principle - DIP): 高层模块不应该依赖于低层模块,两者都应该依赖于抽象。抽象不应该依赖于具体细节,而具体细节应该依赖于抽象。这有助于减少模块之间的紧耦合关系。
这些原则一起形成了 SOLID 的缩写,每个原则都有助于提高软件设计的灵活性、可维护性和可扩展性。在实际编码中,遵循这些原则有助于编写清晰、可读、易于维护的代码。
2.10.1 定义
- 接口和抽象类都是“软件工程产物”
- 具体类 -> 抽象类 -> 接口:越来越抽象,内部实现的东西越来越少
- 抽象类是未完全实现逻辑的类(可以有字段和非 public 成员,它们代表了“具体逻辑”
- 抽象类为复用而生:专门作为基类来使用,也有解耦功能
- 封装确定的,开放不确定的,推迟到合适的子类中去实现
- 接口时完全未实现逻辑的“类”(“纯虚类”;只有函数成员;成员全部 public)
- 接口为解耦而生:“高内聚,低耦合”,方便单元测试
- 接口时一个“协约”,早已为工业生产所熟知(有分工必然有协作,有协作必然有协约)
- 它们都不能被实例化,只能用来声明变量、引用具体类(concrete class)的实例
设计一个父类和两个子类,他们都有重名方法(相同的功能) Run :
目的:使用父类变量调用子类实例,第一种解决方式:使用 virtual 和 override 进行重写:
MyLib1\TransportTools\Car.cs- this.button3.Click += new EventHandler(ButtonClicked);
复制代码 主函数调用:
Program.cs- this.button3.Click += (object sender, EventArgs e) =>
- {
- this.textBox1.Text = "Use Lambda!";
- };
- // 还可以这么写:省略参数类型
- this.button3.Click += (sender, e) =>
- {
- this.textBox1.Text = "Use Lambda!";
- };
复制代码 调用结果:- this.button3.Click += delegate(object sender, EventArgs e)
- {
- this.textBox1.Text = "Use Anonymous delegate, depricated!";
- }
复制代码 可以看到,在这里,基类 Viecle 中的 Run 方法不会被调用到,那么,实际上可以只声明这个方法但不加以实现,具体的实现根据派生类的需求而定。这时候就用到了抽象类(abstract class)和抽象方法(abstract method,又被叫做纯虚方法)。子类在实现抽象方法的时候,要添加 override 关键字,否则编译器会报错。
抽象类专门为作基类而生。- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WPFSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="textBox1" Margin="10,18,10,0" TextWrapping="Wrap" VerticalAlignment="Top" TextAlignment="Center" Height="32"/>
- <Button x:Name="button1" Content="Click Me!" Margin="10,71,10,0" VerticalAlignment="Top" Click="ButtonClicked"/>
- </Grid>
- </Window>
复制代码 2.10.2 接口
再极端一点,有没有一种类,它里面全部方法都是抽象方法?所有的方法否需要后面的类继承了然后去实现?
实际上确实有,这种只含抽象方法(abstract method)的类被称作纯虚类,而纯虚类其实就是接口(interface):
MyLib1\TransportTools\VehicleBase.cs- <Button x:Name="button1" Content="Click Me!" Margin="10,17,10,0" VerticalAlignment="Top" Click="ButtonClicked" />
复制代码 MyLib1\TransportTools\Car.cs:若该类没有实现基类的全部接口,那么要给 class 添加 abstract 关键字- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- namespace WPFSample
- {
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- private void ButtonClicked(object sender, RoutedEventArgs e)
- {
- this.textBox1.Text = "Hello YUZU!";
- }
- }
- }
复制代码 Program.cs- <Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:WPFSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="textBox1" Margin="10,18,10,0" TextWrapping="Wrap" VerticalAlignment="Top" TextAlignment="Center" Height="32"/>
- <Button x:Name="button1" Content="Click Me!" Margin="10,71,10,0" VerticalAlignment="Top" />
- </Grid>
- </Window>
复制代码 因为接口已经隐含了 “纯虚类” 和 “public” 的意思,所以声明时候不允许添加 public abstract
MyLib1\TransportTools\Vehicle.cs- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- namespace WPFSample
- {
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- this.button1.Click += ButtonClicked;
- // this.button1.Click += new RoutedEventHandler(this.ButtonClicked);
- // RoutedEventHandler 和 ButtonClick 遵循相同的约束条件
- }
- private void ButtonClicked(object sender, RoutedEventArgs e)
- {
- this.textBox1.Text = "Hello YUZU!";
- }
- }
- }
复制代码 同时,在实现接口的时候,也需要注意如下几点:
- 未实现的接口,需要写成抽象方法
- 不用写 override 关键字
MyLib1\TransportTools\Car.cs举例:接口类型在实际代码编写中的应用:- using System;using System.Collections;namespace IEnumerableSample{ internal class Program { static void Main(string[] args) { ArrayList a = new ArrayList() { 1, 2, 3, 4, 5, 7.1 }; double res = Sum(a); double ave = Average(a); Console.WriteLine(res); Console.WriteLine(ave); int[] b = new int[] { 1, 2, 3, 4, 5 }; double res1 = Sum(b); // 22.1 double ave1 = Average(b); // 3.683 Console.WriteLine(res1); // 15 Console.WriteLine(ave1); // 3 } public static double Sum(IEnumerable nums) { double sum = 0.0; foreach (var item in nums) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (item is double)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> sum += (double)item;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else if (item is int)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> sum += (int)item;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>// 如果不希望处理其他类型,可以抛出异常<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> throw new InvalidOperationException(<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> $"Unsupported element type {item.GetType().FullName} in collection.");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } return sum; } public static double Average(IEnumerable input) { double sum = 0.0, average = 0.0; int count = 0; foreach (var item in input) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (item is int)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> sum += (int)item;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> count++;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else if (item is double)<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> sum += (double)item;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> count++;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> throw new InvalidOperationException($"Unsupported type {item.GetType()} in collection.");<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } average = sum / count; return average; } }}
复制代码 编译允许结果:- public class OrderEventArgs : EventArgs
- {
- public string DishName { get; set; }
- public string Size { get; set; }
- }
复制代码 C# 中接口的实现
耦合:说们说A和B的耦合度高,意思就是 B 能否正常工作,严重依赖于 A 是否能正常工作,也被称作依赖(Dependencies)。我们设计的类的耦合度过高并不是好事,可能导致局部问题扩大,从而影响全局,或者让代码变得难以调试和维护,错误难以查找。
下面是紧耦合的代码,一个类中有另一个类的字段,且这个字段在该类中广泛被使用,即 Car 的功能严重依赖于 Engine:- // 事件的拥有者
- public class Customer
- {
- private OrderEventHandler orderEventHandler;
- public event OrderEventHandler Order // 包装事件处理器
- {
- // 事件处理器的添加器
- add
- {
- this.orderEventHandler += value;
- }
- // 事件处理器的删除器
- remove
- {
- this.orderEventHandler -= value;
- }
- }
- public double Bill { get; set; }
- public void PayTheBill()
- {
- Console.WriteLine($"I will pay ${this.Bill}");
- }
- // 以下有简写部分
- public void WalkIn(){/*Expression(s)*/}
- public void SitDown(){/*Expression(s)*/}
- public void Think()
- {
- for(int i = 0; i < 5; ++i)
- {
- Console.WriteLine("Let me think!");
- Thread.Sleep(1000);
- }
-
- if(this.orderEventHandler != null)
- {
- OrderEventArgs e = new OrderEventArgs();
- e.DishName = "KFC Chicken Wings";
- e.Size = "large";
- this.orderEventHandler.Invoke(this, e);
- }
- }
-
- // 事件触发的方法
- public void Trigger()
- {
- Console.ReadLine();
- this.WalkIn();
- this.SitDown();
- this.Think();
- }
- }
复制代码 而接口的引入可以显著降低耦合度,使得各模块功能相对独立。
现实生活中,我们拿着任何一部手机都会使用,原因是那些手机的功能都是类似的,手机最基础的功能可以抽象为一个接口。
下面是示例:该例子的代码耦合度很低,我们可以轻易更换使用者使用的手机(iPhone 或 Pixel ),而且我们随时可以创建新的手机给他用(只需要更换传入第 10 行的参数即可),而且编写新的手机类也很容易,只需要实现响应的接口即可。- // 事件响应者
- public class Waiter
- {
- // 实现事件处理器:遵循第一步委托的约束条件
- public void Action(Customer customer, OrderEventArgs e)
- {
- Console.WriteLine("I will serve you {0}", e.DishName);
- double price = 10.0;
- switch (e.Size)
- {
- case "large":
- price = price * 1.5;
- break;
- case "small":
- price = price * 0.8;
- break;
- case "middle":
- price = price;
- break;
- default:
- break;
- }
- customer.Bill += price;
- }
- }
复制代码代码中如果有可以替换的地方,那么一定有接口存在。接口就是为了松耦合而生的,松耦合的最大好处:让功能的提供方变得可替换。
接口的产生:自底向上(重构),自顶向下(设计)
C# 中接口的实现有:隐式、显式、多接口
语言对面向对象设计的内建支持:依赖反转(DIP, Dependency Inversion Principle),接口隔离(ISP, Interface Segregation Principle),开/闭原则(OCP, Open-closed Principle)……
- 依赖反转(DIP)原则的产生,是为了平衡自顶向下这一单一的思维方式
从 紧耦合 -> 松耦合 -> 更松的耦合 的发展方向:引入接口
- 第一步:紧耦合,司机是依赖于车的(因为有车才有司机)
- 第二步:将车的共性提炼成接口 IVehicle ,具体的车的类实现接口;司机类 Driver 包含 IVehicle 的字段,拥有驾驶技能(方法) Drive。此时司机类和 IVehicle 接口依旧是紧耦合的,不过比第一步的耦合程度已经小了很多。
- 第三步:在第二步的基础上,将 Driver 共性的东西提炼成接口 IDriver(该接口有 IVehivle 的字段和 Drive 方法声明),然后由具体类司机类来实现接口,此时司机类因为对 Drive 方法的不同实现,对应现实中不同的驾驶员(如AI驾驶员、小汽车驾驶员、客车驾驶员等)。这一步做到了进一步解耦有。
- 第四步:设计模式
由第一步到第二三步:从依赖具体的汽车种类,到不依赖具体的汽车种类,而是依赖接口,依赖的方向发生了转换,这就是依赖反转(DIP)
单元测试中对接口的使用
如我们要设计一个电扇的类,下面是它的 UML 图示:
---title: 高耦合度---classDiagram PowerSupply ps.GetPower()).Returns(() => 300); using System;
using System.Timers;
namespace EventSample
{
class Program
{
static void Main()
{
// 第一个顾客 customer 点餐
Customer customer = new Customer();
Waiter waiter = new Waiter();
customer.Order += waiter.Action;
customer.Trigger();
// 不怀好意的人badGuy点餐给customer
Customer badGuy = new Customer();
// 仿冒参数e1
OrderEventArgs e1 = new OrderEventArgs();
e1.DishName = "Oyster";
e1.Size = "large";
// 仿冒参数e2
OrderEventArgs e2 = new OrderEventArgs();
e2.DishName = "Mapo Tofu";
e2.Size = "large";
badGuy.Order += waiter.Action;
// 绕过Customer类的逻辑,直接触发事件(制造了仿冒的参数e1和e2并进行传递)
badGuy.Order.Invoke(customer, e1);
badGuy.Order.Invoke(customer, e2);
customer.PayTheBill();
}
}
public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
// 事件响应者
public class Waiter
{
public void Action(Customer customer, OrderEventArgs e)
{
Console.WriteLine("I will serve you {0}", e.DishName);
double price = 10.0;
switch (e.Size)
{
case "large":
price = price * 1.5;
break;
case "small":
price = price * 0.8;
break;
case "middle":
price = price;
break;
default:
break;
}
customer.Bill += price;
}
}
// 事件消息类:继承 EventArgs
public class OrderEventArgs: EventArgs
{
public string DishName{get; set;}
public string Size{get; set;}
}
// 事件拥有者
public class Customer
{
public static double Bill{get; set;}
public OrderEventHandler Order // 将事件当作字段来使用
public void WalkIn()
{
Console.WriteLine("Walk into KFC...");
}
public void SitDown()
{
Console.WriteLine("Sit Down.");
}
public void Think()
{
for(int i = 0; i < 5; ++i)
{
Console.WriteLine("Let me think!");
Thread.Sleep(1000);
}
if(this.orderEventHandler != null)
{
OrderEventArgs e = new OrderEventArgs();
e.DishName = "KFC Chicken Wings";
e.Size = "large";
this.orderEventHandler.Invoke(this, e);
}
}
public void PayTheBill()
{
Console.WriteLine("I will pay you ${0}", this.Bill);
}
// 事件触发方法
public void Trigger()
{
Console.ReadLine();
this.WalkIn();
this.SitDown();
this.Think();
}
}
} string expected = "warning!"; string actual = fan.Work(); Assert.Equal(expected, actual); } }}[/code]解释如下代码:- using System;
- using System.Timers;
- namespace EventSample
- {
- class Program
- {
- static void Main()
- {
- // ...
- }
- }
-
- public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);
-
- public class Waiter
- {
- public void Action(Customer customer, OrderEventArgs e)
- {
- // ...
- }
- }
- public class OrderEventArgs: EventArgs
- {
- // ...
- }
-
- // 事件拥有者
- public class Customer
- {
- public static double Bill{get; set;}
- public event OrderEventHandler Order; // 事件的简略声明,不是字段!
- // ...
-
- public void Think()
- {
- //...
-
- if(this.Order != null) // 修改后
- {
- OrderEventArgs e = new OrderEventArgs();
- e.DishName = "KFC Chicken Wings";
- e.Size = "large";
- this.Order.Invoke(this, e); // 修改后
- }
- }
-
- // ...
- }
- }
复制代码 使用Setup方法配置IPowerSupply接口中的GetPower方法。在这里,设置GetPower方法的返回值为-1。创建了一个DeskFan对象,通过传入上面创建的模拟的IPowerSupply实例。这里通过mock.Object获取了模拟的实例。
注意:编写测试用例和编写功能代码拥有同等的重要性,因为要保证代码功能正确
2.10.3 反射和依赖注入
接口隔离
接口隔离原则(ISP)的核心是:将本质不同的功能隔离开,然后再用接口封装起来。
接口隔离原则一
Clients should not be forced to depend upon interfaces that they don't use.
不应该强行要求客户端依赖它们不需要使用的接口。
一个类不应该被迫依赖它不使用的接口。调用者不能要不使用的方法,如果接口中有一个或者多个没有使用到,说明违反了接口隔离原则,也说明接口的设计过大,不合理。
解决方案:将过大的接口拆分成更小的多个接口。 下面给出一个示例:定义一个 Vehicle 接口,它有 Run 这个功能。而坦克也有 Run 这个功能,但是它还能开火,这个功能名为 Fire。
有一个驾驶员,他能开车也能开坦克,但是他在常规情况下不会使用坦克开火,而是把它像车一样开。按照我们先前的设计:
Vehicle.cs- Walk into the restaurant
- Sit Down
- Let me think...
- Let me think...
- Let me think...
- Let me think...
- Let me think...
- I will serve you the dish: KFC Chicken Wings
- I will serve you the dish: Oyster
- I will serve you the dish: Mapo Tofu
- I will pay $45
复制代码 这里定义了 Vehicle 接口,并有两个该接口的具体实现
Tank.cs- using System;
- using System.Threading;
- namespace EventDeclareSample
- {
- // ...
- public class Waiter
- {
- public void Action(object sender, EventArgs e)
- {
- // 类型转换:直接使用C#自带的委托类型,但要进行类型转换
- Customer customer = sender as Customer;
- OrderEventArgs orderInfo = e as OrderEventArgs;
-
- Console.WriteLine($"I will serve you the dish: {orderInfo.DishName}");
- double price = 10;
- switch (orderInfo.Size)
- {
- case "small":
- price = price * 0.5;
- break;
- case "large":
- price = price * 1.5;
- break;
- default:
- break;
- }
- customer.Bill += price;
- }
- }
-
- }
复制代码 这里我们定义了一个基接口 IWeapon ,另一个接口 ITank 继承了基接口 IWeapon 和 IVehicle。如第 8 行代码。这样做的目的是后续调用的时候降低耦合度。
第一种违反接口隔离原则的情况:如果不做接口隔离会怎么样?
如果不拆分 ITank接口(不做接口隔离),那么它是这样的:这里面有两个功能 Run 和 Fire,而功能 Fire 我们永远用不上
到时候 Driver 类中就要有一个 ITank 字段和 IVehicle 字段,明显就增加了耦合度不说。还需要繁琐的写法才能解决两个字段中 Run 方法调用的问题。
或者直接使用 ITank 替换了 IVehicle 字段,但这样构造函数和 Run 方法中的响应位置都要重写,如果被引用的次数过多,那么将是灾难性的问题。
而遇到了这种两个功能相差极大的接口,我们可以拆分它,从而达到接口隔离的目的
这里还有三个类,都实现了接口 ITank。
Driver.cs- using System;
- using System.Threading;
- namespace EventDeclareSample
- {
- // ...
- public class Customer
- {
- // ...
- public void Think()
- {
- for (int i = 0; i < 5; ++i)
- {
- Console.WriteLine("Let me think...");
- Thread.Sleep(1000);
- }
- this.OnOrder("KFC Chicken Wings", "large"); // 调用事件的触发方法
- }
- public void Trigger()
- {
- // ...
- }
-
- // 事件的方法名:OnOrder
- protected void OnOrder(string dishName, string size)
- {
- // 一定要判断事件封装的委托是否为空
- if (this.Order != null)
- {
- OrderEventArgs e = new OrderEventArgs();
- e.DishName = dishName;
- e.Size = size;
- this.Order.Invoke(this, e); // 事件必须要求事件拥有者触发,所以在这里传递 this
- }
- }
- }
- public class OrderEventArgs : EventArgs
- {
- // ...
- }
- public class Waiter
- {
- public void Action(object sender, EventArgs e)
- {
- // ...
- }
- }
- }
复制代码 Program.cs- using System;
- namespace HelloClass
- {
- class Student
- {
- public static int Amount { get; private set; }
- public string Name { get; set; }
- public int ID { get; set; }
-
- // 创建自己的实例构造器:看起来像一个方法,但是没有返回值。快捷键:ctor + Enter
- public Student(string name, int id)
- {
- this.Name = name;
- this.ID = id;
- Amount++;
- }
-
- // 实例析构器
- ~Student()
- {
- Amount--;
- Console.WriteLine("Bye, Releasing System Resources ...");
- }
-
- // 静态构造器:只能构造静态成员
- static Student()
- {
- Amount = 0;
- }
- public void Report()
- {
- Console.WriteLine($"I'm No.{this.ID} student, my name is {this.Name}");
- }
- }
- }
复制代码 编译运行结果:- using System;
- namespace HelloClass
- {
- internal class Program
- {
- public static void Main(string[] args)
- {
- // 1.使用实例构造器创建对象
- Student stu1; // 声明变量
- // stu1 = new Student() { Name = "Yuzu", ID = 12 }; // 创建实例,调用默认构造器
- stu1 = new Student("Yuzu", 12); // 使用自建实例构造器,stu1 为 Student 类的实例
- Console.WriteLine(stu1.Name); // Yuzu
- Console.WriteLine(stu1.ID); // 12
- stu1.Report();
-
- // 2.使用反射创建实例:充分展现类的类型一面
- Type t = typeof(Student); // 拿到类型信息
- // 使用类型信息创建实例 o, CreateInstance 创建的实例都为 object 类型
- object o = Activator.CreateInstance(t, "Aoko", 1);
- // 此时 o 类型已经丢失了很多信息,但是它的类型名字还是 Student,说明可以找回来
- Console.WriteLine(o.GetType().Name); // Student
- // 转换为 Student 类型
- Student s = o as Student;
- s?.Report();
-
- // 3.使用 dynamic 创建实例
- Type t1 = typeof(Student);
- dynamic stu2 = Activator.CreateInstance(t1, "Shizuku", 18);
- Console.WriteLine(stu2.Name); // Shizuku
- Console.WriteLine(Student.Amount); // 3
- }
- }
- }
复制代码 上述代码 Program.cs 的第 13 行:因为继承了 ITank 接口,而 ITank 继承了 IVehicle 和 IWeapon ,所以类 HeavyTank 中实现了 IVehicle。故这里传入的时候不会报错。
注意:过犹不及,请注意不要产生很细碎的单一功能的接口和类。颗粒度太小的接口和类会产生另外的问题。所以要将接口和类的大小控制在一定的范围之内。
接口隔离原则二
The dependency of one class to another one should depend on the smallest possible interface.
类之间的依赖应该建立在最小的接口上。
即:调用者绝不多调。下面我们自定义了一个只读的集合类,它实现了 IEnumerable 接口,相当于它是 IEnumerable 的一个封装。而计算和的方法 Sum 一开始接收一个 ICollection 类型的参数(ICollection 参数也继承了 IEnumerable ,不严谨的说,它和 ReadonlyCollection 是同级别,都是 IEnumerable 的子接口(类))。
因为 ICollection 实现的方法更多,所以要求比 IEnumerable 更严格(但是多余的方法在这里没有用处),它要求传入的参数要实现它的所有方法:
而在 Sum 方法中,我们只用得上迭代方法,其他的方法都用不上,所以不需要将类型设置为 ICollection ,因为这样会把很多使用者“挡”在外面。故将他更换为更小的接口 IEnumerable。下面是实现的具体代码:
LSPSample2.cs- using System;using System.Collections;namespace MyReadonlyEnumerator{ internal class Program { public static void Main(string[] args) { int[] nums1 = { 1, 2, 3, 4, 5 }; IEnumerable nums3 = new ReadonlyCollection(nums1); // 使用接口接收子类成员 foreach (var item in nums3) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>Console.WriteLine(item); } int res = Sum(nums3); Console.WriteLine(res); } // static int Sum(ICollection nums) static int Sum(IEnumerable nums) // ICollection 太大,而这里服务使用者只使用迭代,不需要其他的功能: { int sum = 0; foreach (var item in nums) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>sum += (int)item; } return sum; } } // 定义并实现一个只读集合类,实现IEnumerable接口 public class ReadonlyCollection : IEnumerable { private int[] _inputArray; public ReadonlyCollection(int[] inputArray) { this._inputArray = inputArray; } public IEnumerator GetEnumerator() // 接口IEnumerable中待实现的方法 { return new Enumerator(this); } // 为了实现 IEnumerable 接口的方法,要定义一个Enumerator类,继承 IEnumerator 接口 // 其防止名称污染,所以定义在类种 class Enumerator : IEnumerator { private ReadonlyCollection _readonlyCollection; private int _head; public Enumerator(ReadonlyCollection readonlyCollection) {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>this._readonlyCollection = readonlyCollection;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>_head = -1; } public bool MoveNext() {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>if (++_head < _readonlyCollection._inputArray.Length) // 因为在另一个类中,所以可以访问外层类的成员<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return true;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>}<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>else<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return namespace IndexerSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s1 = new Student("math", 60);
- var mathScore = s1["math"];
- Console.WriteLine(mathScore);
- s1["English"] = 95;
- s1["Physics"] = 80;
- Console.WriteLine(s1["Physics"]);
- }
- }
- class Student
- {
- public Student(string key, int val)
- {
- scoreDict[key] = val;
- }
- private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
- public int? this[string subject] // this 为可空类型
- {
- get
- {
- if (scoreDict.ContainsKey(subject))
- {
- return scoreDict[subject];
- }
- else
- {
- return null;
- }
- }
- set
- {
- if (!value.HasValue)
- {
- throw new Exception("Score cannot be null");
- }
- else
- {
- if (scoreDict.ContainsKey(subject))
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict[subject] = value.Value;
- }
- else
- {
- namespace ParameterSample
- {
- internal class Program
- {
- static void Main(string[] args)
- {
- Student s2 = new Student() { Name = "Mio" };
- UpdateObject(s2);
- Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
- }
- public static void UpdateObject(Student s)
- {
- s.Name = "Kamigami"; // 避免修改值,较为少用
- Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
- }
- }
- class Student
- {
- public string Name { get; set; }
- }
- }scoreDict.Add(subject, value.Value);
- }
- }
- }
- }
- }
- };<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } public void Reset() {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>_head = -1; } public object Current {<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>get<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>{<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> object o = _readonlyCollection._inputArray[_head];<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window> return o;<Window x:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:EventSample"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Grid>
- <TextBox x:Name="timeTextBox" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="800" Height="139" TextAlignment="Center" FontSize="36"/>
- </Grid>
- </Window>} } } }}
复制代码 对上面代码进行解释:
这段代码演示了一个只读集合(ReadonlyCollection)和一个用于计算集合元素和的方法(Sum)。以下是代码的解释:
- ReadonlyCollection 类:
- 这是一个实现了 IEnumerable 接口的只读集合类。
- 构造函数接受一个整数数组 inputArray 作为参数,并将其存储在私有字段 _inputArray 中。
- 实现了 IEnumerable 接口的 GetEnumerator 方法,返回一个自定义的迭代器 Enumerator 的实例。
- Enumerator 类:
- 迭代器用于在只读集合上遍历元素。
- 构造函数接受一个 ReadonlyCollection 实例作为参数,并将其存储在私有字段 _readonlyCollection 中。迭代器的初始位置 _head 设为 -1。
- MoveNext 方法用于移动迭代器到下一个元素,如果还有元素未遍历,则返回 true,否则返回 namespace IndexerSample
{
internal class Program
{
static void Main(string[] args)
{
Student s1 = new Student("math", 60);
var mathScore = s1["math"];
Console.WriteLine(mathScore);
s1["English"] = 95;
s1["Physics"] = 80;
Console.WriteLine(s1["Physics"]);
}
}
class Student
{
public Student(string key, int val)
{
scoreDict[key] = val;
}
private Dictionary<string, int> scoreDict = new Dictionary<string, int>();
public int? this[string subject] // this 为可空类型
{
get
{
if (scoreDict.ContainsKey(subject))
{
return scoreDict[subject];
}
else
{
return null;
}
}
set
{
if (!value.HasValue)
{
throw new Exception("Score cannot be null");
}
else
{
if (scoreDict.ContainsKey(subject))
{
namespace ParameterSample
{
internal class Program
{
static void Main(string[] args)
{
Student s2 = new Student() { Name = "Mio" };
UpdateObject(s2);
Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
}
public static void UpdateObject(Student s)
{
s.Name = "Kamigami"; // 避免修改值,较为少用
Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
}
}
class Student
{
public string Name { get; set; }
}
}scoreDict[subject] = value.Value;
}
else
{
namespace ParameterSample
{
internal class Program
{
static void Main(string[] args)
{
Student s2 = new Student() { Name = "Mio" };
UpdateObject(s2);
Console.WriteLine($"Name = {s2.Name}, HashCode = {s2.GetHashCode()}");
}
public static void UpdateObject(Student s)
{
s.Name = "Kamigami"; // 避免修改值,较为少用
Console.WriteLine($"Name = {s.Name}, HashCode = {s.GetHashCode()}");
}
}
class Student
{
public string Name { get; set; }
}
}scoreDict.Add(subject, value.Value);
}
}
}
}
}
}。
- Reset 方法将迭代器重置到初始位置。
- Current 属性返回当前元素的值。
接口隔离原则三
展示 C# 语言的独特能力:显式接口实现,C# 语言不仅能够做到接口隔离,还能够将隔离的接口隐藏起来,直到我们显式使用一个该接口类型的变量去引用实现了该接口的实例为止。
如一个方法不能轻易被外部调用,那么就不能轻易暴露出来,这时候就需要显式的实现了,否则普通实现就很容易暴露这些重要接口。(如一个杀手走在大街上,不能被轻易的看出是杀手一样)
普通实现的代码:- Error CS0656 : 缺少编译器要求的成员“Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create”
复制代码 编译运行结果:- // 创建自己的实例构造器:看起来像一个方法,但是没有返回值。快捷键:ctor + Enter
- public Student(string name, int id)
- {
- this.Name = name;
- this.ID = id;
- Amount++; // 每创建一个实例,Amount自增一次
- }
复制代码 效果:轻易暴露接口
而显式实现就能够做到重要接口隐藏,正如杀手平时不会让别人看出自己是杀手,而当接到任务的时候才能被看出来,而对被猎杀的对象是不需要抱有仁慈之心的。
来源:https://www.cnblogs.com/kobayashilin1/p/17985892
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|