C#第4章面向对象编程基础.ppt_第1页
C#第4章面向对象编程基础.ppt_第2页
C#第4章面向对象编程基础.ppt_第3页
C#第4章面向对象编程基础.ppt_第4页
C#第4章面向对象编程基础.ppt_第5页
已阅读5页,还剩66页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 第4章 面向对象的编程基础 4.1 类 4.2 结构 4.3 方法 4.4 属性与索引器 2 C#是一种强大的、面向对象的程序开发语言,本章将带 领读者进入C#面向对象的世界,学习一些基本概念,包 括对象、类等,以及如何创建和使用类的对象。 为什么要学习对象和类? 举个简单的例子:汽车厂造车需要设计图和样板,然后造 出汽车。编程也是一样的,类好比是制造汽车的设计图 和样板,对象好比是汽车,这都是汽车厂不可或缺的东 西。 第4章 面向对象的编程基础 3 在现实世界中,对象就是拥有了这些特性和动作才会在这 个世界上变得与众不同。因此,构成对象的两个最重要的 因素就是特征和动作。每一个现实世界中的实体都具有不 同的特征和动作。 在编程领域,编程开发人员需要尽可能地用对象来模拟现 实世界的实体,因此,在程序里,对象具有状态和行为。 对象的状态就是现实世界中对应实体的属性特征,对象的 行为就是现实世界中对应实体能够执行的动作。 在 C#中,对象的状态被分别存储在一些变量里,而对象的 行为,则通过定义方法来实施。方法的作用就是要完成一 项特殊的工作。 第4章 面向对象的编程基础 4 知识点 对象:明白对象的属性和方法,学会使用对象。 类:辨别对象和类,明白类的属性和方法,了解 类的成员。 属性:学会在类中添加属性,保护数据安全,以 及封装字段。 结构:如何创建结构,结构和类有什么区别? 索引器:会使用索引器 5 4.1 类 类与对象 类:一组具有相同数据结构和相同操作的对象的集合。 例如:汽车 对象(实例):类的实例化 。例如:卡车 注意:要使用对象,必须先定义类,然后再创建对象。 对象的生存周期 对象在建立时分配了内存,创建对象实际上作了两个方面的工作 : (1)使用new保留字要求系统分配内存; (2)使用构造函数初始化数据。 销毁对象也是做了两个方面的工作: (1)释放占用的内存; (2)将分配给对象的内存归还给堆(Heap)。 6 4.1 类的组织 1.类的声明 用class定义类,声明类的形式为: 附加声明 访问修饰符 class 类名称:基类 ,接口序列 字段声明 构造函数 方法 事件 注意:中的内容可省或任 选其一,当两者都有时,先基 类后接口 7 4.1 类的组织(续) public class Child private int age; private string name; / 不带参数的构造函数 public Child() name = “none“; / 带参数的构造函数 public Child(string name, int age) 如果不指明,则 默认为internal 8 4.1 类的组织(续) = name; this.age = age; / 输出方法 public void PrintChild() Console.WriteLine(“0, 1 years old.“, name, age); public class Program 9 4.1 类的组织(续) public static void Main() /使用new关键字创建对象,new后是调用的构造 函数 Child child1 = new Child(“Zhang San“, 11); Child child2 = new Child(“Li Si“, 10); Child child3 = new Child(); / 显示结果 Console.Write(“Child #1: “); child1.PrintChild(); Console.Write(“Child #2: “); child2.PrintChild(); Console.Write(“Child #3: “); child3.PrintChild(); 10 4.1 类的组织(续) Console.ReadLine(); 输出结果: Child #1: Zhang San, 11 years old. Child #2: Li Si, 10 years old. Child #3: none, 0 years old. 11 c#中this的用法 1、表示对象的当前实例。如果实例成员具有与形参相同的名称,则可以这 样使用以示区别。 2、将当前对象作为形参传递到其他方法中 class Employee private string name; private string alias; private decimal salary = 3000.00m; / Constructor: public Employee(string name, string alias) / Use this to qualify the fields, name and alias: = name; this.alias = alias; 12 / Printing method: public void printEmployee() Console.WriteLine(“Name: 0nAlias: 1“, name, alias); / Passing the object to the CalcTax method by using this: Console.WriteLine(“Taxes: 0:C“, Tax.CalcTax(this); public decimal Salary get return salary; class Tax public static decimal CalcTax(Employee E) return 0.08m * E.Salary; 3、声明索引器 。由于静态成员函数存在于类一级,并且不是对象的一部分 ,因此没有 this 指针。在静态方法中引用 this 是错误的。 c#中this的用法 13 静态类 l 类可以声明为 static 的,以指示它仅包含静态成员。不 能使用 new 关键字创建静态类的实例。静态类在加载包 含该类的程序或命名空间时由 .NET Framework 公共语言运 行库 (CLR) 自动加载。 l 使用静态类来包含不与特定对象关联的方法。例如,创建一 组不操作实例数据并且不与代码中的特定对象关联的方法, 这种情况下应该使用静态类来包含那些方法。 l 静态类的主要功能如下: 它们仅包含静态成员。 它们不能被实例化。 它们是密封的。 它们不能包含实例构造函数(C# 编程指南)。 14 使用静态类的优点在于,编译器能够执行检查以确保不致偶 然地添加实例成员。编译器将保证不会创建此类的实例。 静态类是密封的,因此不可被继承。静态类不能包含构造函 数,但仍可声明静态构造函数以分配初始值或设置某个静态 状态。 使用静态类作为不与特定对象关联的方法的组织单元。此外 ,静态类能够使实现更简单、迅速,因为不必创建对象就能 调用其方法。以一种有意义的方式组织类内部的方法(例如 System 命名空间中的 Math 类的方法)是很有用的。 静态类 15 static class CompanyInfo public static string GetCompanyName() return “CompanyName“; public static string GetCompanyAddress() return “CompanyAddress“; /. 静态类 16 4.1.2 构造函数 作用:构造函数是一个特殊的方法,用于在建立对象时 为对象分配存储空间,对数据成员进行初始化。 好处:确保每一个对象在被使用之前都适当地进行了初始 化的动作。 构造函数特点: 1) 每个类至少有一个构造函数。若程序代码中没有构造函 数则系统会自动提供一个默认的构造函数。 2) 一个构造函数总是和它的类名相同。 3) 构造函数不包含任何返回值。 4) 构造函数总是public的。 一般在构造函数中作初始化工作,对于执行过程用时比较 长的程序代码,最好不要放在构造函数中。 5)必须使用操作符 new 来调用一个构造函数 17 4.1.2 构造函数(续) 1、默认构造函数 (1)如果在类中不定义构造函数,系统会提供一个默认的构 造函数。 (2)默认构造函数没有参数。 (3)默认构造函数自动将非静态成员初始化为: 数值型:如int、double等,初始化为0。 bool类型:初始化为false. 引用类型:初始化为null。 (4)如果自己定义了类的构造函数,则所有初始化工作由编 程者自己完成。 18 4.1.2 构造函数(续) 2. 重载构造函数 有时候可能会遇到这样的情况:在一个类中的多个方 法中都要用到某一个数据成员,而该成员值必须从其他类 中传递过来。这时,无参数的构造函数就不能胜任了,解 决这个问题最好的办法就是:重载(Overloading)构造函 数。 19 4.1.2 构造函数(续) using System; using System.Collections.Generic; using System.Text; namespace OverloadingExample class Program public Program() Console.WriteLine(“null“); 20 4.1.2 构造函数(续) public Program(string str) Console.WriteLine(str); static void Main() Program aa = new Program(); Program bb = new Program(“How are you!“); Console.ReadLine(); 21 复制构造函数 某些编程语言的类提供了复制构造函数,即从当前类实例 构造一个新的类实例。在C#编程语言中,没有提供复制构造函 数,如果要实现复制构造的功能,就必须自行编写这样的构造 函数。 C#复制构造函数仍然属于构造函数,不同的是以类 本身作为参数的数据类型。 调用复制构造函数时,参数必须是已经创建的类实例 。 Contact c1 = new Contact(“lisi“); Contact c2 = new Contact(c1); 4.1.2 构造函数(续) 22 4.1.3 字段和局部变量 字段:指声明为类一级的对象或值类型的变量。 局部变量:指在方法、事件以及构造函数内声明的变量。 public class Program public static int j=20; /字段 public static void Main() int j=30; /局部变量 Console.WriteLine(j); /输出结果:30 Console.WriteLine(Program.j); /输出结果:20 Console.ReadLine(); 23 4.1.3 字段和局部变量 当字段和局部变量名相同时,如果要引用静态字段,可 以使用下面的形式: 类名.字段名 如果是实例字段,则使用下面的形式: this.字段名 这里的this指当前实例。 当然,如果没有出现字段和局部变量名重名的情况下,引 用字段的形式和引用局部变量的形式相同。 24 4.1.4 静态成员与实例成员 类的成员包括字段、属性、构造函数、方法、事件、索引、嵌套 类。 类的成员分静态成员和实例成员 静态成员在内存中只有一份 静态成员要等到应用程序结束时才会退出内存。 把只有创建了类的实例才能够使用的成员叫实例成员。 静态成员作用: 1、需要在一个类的各个对象间交互,即需要一个数据对象为整 个类而非某个对象服务。 2、同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部 ,对外不可见。 类的static成员具有如下特征:有独立的存储区,属于整个类。 25 注意: 1、对于静态的数据成员,连接器会保证它拥有一个单一 的外部定义。静态数据成员按定义出现的先后顺序依次初始化 ,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。 消除时的顺序是初始化的反顺序。 2、类的静态成员函数是属于整个类而非类的对象,所以 它没有this指针,这就导致了它仅能访问类的静态数据和静态 成员函数。 4.1.4 静态成员与实例成员 26 4.1.5 访问修饰符 C#中有以下成员访问修饰符: Public (常用)任何外部的类都可以不受限制的存取这个类的方法和 数据成员。 private (常用)类中的所有方法和数据成员只能在此类中使用,外部 无法存取。(默认) Protected 除了让本身的类可以使用之外,任何继承自此类的子类都可 以存取。 Internal 在当前项目中都可以存取。该访问权限一般用于基于组件的开 发,因为它可以使组件以私有方式工作,而该项目外的其它代码无法访 问。类的访问修饰符默认为Internal Protected internal 只限于当前项目,或者从该项目的类继承的类才 可以存取。 Partial 局部类型,类的定义和实现可以分布在多个文件中,但都要使 用partial标注,基类只需要声明一次,若多次声明则必须完全一致。 27 命名空间隐式地具有 public 已声明可访问性。在命名空间声 明中不允许使用访问修饰符。 编译单元或命名空间中声明的类型可以具有 public 或 internal 已声明可访问性,默认的已声明可访问性为 internal。 类成员可具有五种已声明可访问性中的任何一种,默认为 private 已声明可访问性。(请注意,声明为类成员的类型可 具有五种已声明可访问性中的任何一种,而声明为命名空间成 员的类型只能具有 public 或 internal 已声明可访问性。) 枚举成员隐式地具有 public 已声明可访问性。在枚举成员声 明中不允许使用访问修饰符。 4.1.5 访问修饰符 28 结构成员可以具有 public、internal 或 private 已声明可访 问性并默认为 private 已声明可访问性,这是因为结构是隐式 地密封的。结构的成员若是在此结构中声明的(也就是说,不是 由该结构从它的基类中继承的)不能具有 protected 或 protected internal 已声明可访问性。(请注意,声明为结构 成员的类型可具有 public、internal 或 private 已声明可访 问性,而声明为命名空间成员的类型只能具有 public 或 internal 已声明可访问性。) 接口成员隐式地具有 public 已声明可访问性。在接口成员声明 中不允许使用访问修饰符。 4.1.5 访问修饰符 29 局部类型partial C# 2.0 引入了局部类型的概念。局部类型允许我们将一个 类、结构或接口分成几个部分,分别实现在几个不同的.cs 文件中。 局部类型适用于以下情况: (1) 类型特别大,不宜放在一个文件中实现。 (2) 一个类型中的一部分代码为自动化工具生成的代码, 不宜与我们自己编写的代码混合在一起。 (3) 需要多人合作编写一个类。 局部类型是一个纯语言层的编译处理,不影响任何执行机制 事实上C#编译器在编译的时候仍会将各个部分的局部类 型合并成一个完整的类。 30 2. 局部类型的限制 (1) 局部类型只适用于类、接口、结构,不支持委托和枚举。 (2) 同一个类型的各个部分必须都有修饰符 partial。 (3) 使用局部类型时,一个类型的各个部分必须位于相同的命 名空间中。 (4) 一个类型的各个部分必须被同时编译。 局部类型partial 31 partial 3. 局部类型的注意点 (1) 关键字partial是一个上下文关键字,只有和 class、 struct、interface 放在一起时才有关键字的含义。因此 partial的引入不会影响现有代码中名称为partial的变量。 (2) 局部类型的各个部分一般是分开放在几个不同的.cs文件 中,但C#编译器允许我们将他们放在同一文件中。 32 4.2 结构 结构(struct)是由一系列相关的、但类型不一定相同的变 量组织在一起而构成的数据表示形式,所有结构类型都隐式 地从类型object继承。通常用来封装小型相关变量组,例如 ,矩形的坐标或库存商品的特征。 例如:public struct Point public int x; public int y; public string s; C#中的结构:DateTime/TimeSpan/Point/Int32/Double等 33 在结构声明中,除非字段被声明为 const 或 static,否则 无法初始化。 结构不能声明默认构造函数(没有参数的构造函数)或析构 函数。 结构在赋值时进行复制。 将结构赋值给新变量时,将复制 所有数据,并且对新副本所做的任何修改不会更改原始副本 的数据。 凡是定义为结构的,都可以用类来定义。 创建轻量级对象时,可以使用结构。 4.2 结构 34 结构是值类型,而类是引用类型。 与类不同,结构的实例化可以不使用 new 运算符。 结构可以声明带参数的构造函数。 一个结构不能从另一个结构或类继承,而且不能作为一个类 的基。 结构可以实现接口。 结构可用作可以为 null 的类型,因而可向其赋 null 值。 结构不能包含显式的无参数构造函数。 Class的构造函数不需要初始化全部字段,Struct的构造函数 必须初始化所有字段 4.2 结构 35 结构 结构类 没有默认的(无参数)构造函数,但是可 以添加构造函数,结构可以声明构造函数 ,但是他们必须是带参数的。 有默认的构造函数 没有析构函数有析构函数 没有abstract和sealed(因为不能继承)可以使用abstract和sealed 不能有protected修饰符,不可以声明 protected,virtual,sealed和override成员 可以声明protected,virtual ,sealed,override成员 36 结构 结构类 可以不使用new初始化,struct在 声明时就进行了初始化过程,所 有的成员变量均默认为0或null 必须使用new初始化 在结构中初始化实例字段是错误 的 Struct变量使用完之后就自动解除 内存分配 Class实例有垃圾回收机制 来保证内存的回收处理 Struct创建的对象复制简单,直 接以等号连接即可 Class对象复制分为浅复制 和深复制,必须经过 特别 的方法来完成复制 37 结构 使用场合: (1)实现一个主要用于底层存储数据类型的结构时,可以考虑 结构。将用于定义应用程序行为的类型设计为Class。 (2)Struct变量占用堆栈的空间,因此适用于数据量相对小的 场合,堆栈的空间有限,对于大量的逻辑的对象,创建类要比创 建结构好一些。 (3)结构数组具有更高的效率 (4)结构表示如点,矩形和颜色这样轻量的对象,例如,如果 声明一个含有1000个点的对象数组,则将为引用每个对象分配附 加的内存,在此情况下,结构的成本较低。 (5) 在表现抽象和多级别的对象层次时,类是最好的选择 38 4.3 方法 方法(Method)是一组程序代码的集合,每个方法都有一个 方法名,便于识别和让其他方法调用。 1. 方法的定义与使用 (1)方法必须放在某个类中。 (2)定义方法的语法形式为: 访问修饰符 返回值类型 方法名称(参数序列) 语句序列 39 4.3 方法(续) 定义方法时,需要注意以下几点: 方法名不能和变量、常数或者任何声明在类中其它的成员相同 。 方法可以有参数,也可以没有参数,但是不论是否有参数,小 括号都是必需的。如果参数序列中的参数有多个,则以逗号分 开。 结束某个方法的执行,可以使用return语句,程序遇到return 语句后,会将执行流程交还给调用此方法的程序代码段。此外 ,还可以用return语句返回一个值。 如果声明一个非void类型的方法,则方法中必须至少有一个 return语句。 40 4.3 方法(续) using System; class Program public int MyMethod() Console.WriteLine(“this is MyMethod.“); int i = 10; return i; static void Main() Program method = new Program(); int j = 5; j = method.MyMethod(); Console.WriteLine(“the value is 0.“, j); 41 2. 方法中的参数传递 1) 传递值类型的参数 形参(parameter):表示定义方法的参数 实参(argument):表示实际用于调用方法的参数 C#中所有的实参默认按值传递,换句话说,被调用方法获得 传入的实参值的副本。 值类型参数的格式为: 参数类型 参数名 4.3 方法 42 4.3 方法 class Program public static void AddOne(int x)x+; static void Main() int a = 3; Console.WriteLine(“调用AddOne之前,a=0“, a); AddOne(a); Console.WriteLine(“调用AddOne之后,a=0“, a); Console.ReadLine(); 43 4.3 方法(续) 2) 传递引用类型的参数 引用类型参数的格式为: ref 参数类型 参数 如果在方法中改动按引用传入的变量,则会修改这些变量的 值。不能将字面值作为实参传入要求按引用传入形参的方法 。 class Program public static void AddOne(ref int x)x+; static void Main() int a = 3; Console.WriteLine(“调用AddOne之前,a=0“, a); AddOne(ref a); Console.WriteLine(“调用AddOne之后,a=0“, a); Console.ReadLine(); 44 4.3 方法(续) 3) 输出多个引用类型的参数 输出引用类型参数的格式为: out 参数类型 参数名 目的是完全使用变量获得来自于方法的一些返回值。 class Program public static void MyMethod(out int a, out int b) a = 5; b = 6; static void Main() int x, y; MyMethod(out x, out y); Console.WriteLine(“调用MyMethod之后,x=0,y=1“, x, y); Console.ReadLine(); 45 Ref参数传递与Out参数传递异同点 相同点: 都是传递引用类型的参数,编译器处理时没有区别 不同点: Ref参数使用前必须要初始化 Out参数使用前不必初始化 注意: public void AddOne(ref int x) public void AddOne(out int x) 上面这两个方法,不是重载方法。 46 4.3 方法(续) 4) 传递个数不确定的参数 需要传递的参数个数不确定时,可以采用params关键字,其 后一般跟一个数组。 例如: class Program public static float Average(params long v) long total, i; for (i = 0, total = 0; i 0) number = value; /value是关键字,其值由编 译器自动生成,包含了set存取器赋予的值。 51 4.4.1 属性(续) public class Program public static void Main() MyClass me = new MyClass(); Console.WriteLine(me.MyNumber); me.MyNumber = 5; Console.WriteLine(me.MyNumber); Console.ReadLine(); 52 /MyClass.cs using System; namespace ConsoleTest class MyClass private int number; public int Number get return number; set if (value 0) number = value; /Program.cs using System; namespace ConsoleTest public class Program public static void Main() MyClass me = new MyClass(); me.Number = -1; Console.WriteLine( “Number:0“, me.Number); Console.ReadLine(); 回答:Number输出的值是多少? 53 封装有如下好处: l 避免使用非法数据赋值。 l 保证数据的完整性。 l 避免类内部发生修改时,导致整个程序的修改。 4.4.1 属性(续) 54 快速创建属性 属性在 C#开发中使用的非常普遍的,除了手动输入代码 以外,VS 还提供了一个快捷的方法:重构封装字段。 在一个类中,定义一个字段,通常设定为私有,选中这个字 段并右击,在弹出的书生菜单中选择【重构】【封装字段 命令,如下页左图所示。封装结束后就会弹出一个窗口,可 以修改属性名,单击【确定】按钮就会将选择的字段与属性 关联,如下页右图所示。确定后创建和选定字段关联的属性 ,也可以称为将字段封装。 4.4.1 属性(续) 55 4.4.1 属性(续) 56 我们知道数组中的元素可以通过索引进行检索,如果一个类 中有很多对象,怎样简单快速地查找到需要的对象以及对象 的特性呢?索引器就是为了实现这样的功能而设计的。索引 器允许类或者结构的实例可以按照数组那样进行索引。可以 简单地把索引器理解为常见的书中的目录,字典中提供检索 的索引。 您查过字典吗?这个问题太幼稚了,相信大家都查过字典, 无论新华字典还是成语词典都提供了检索方法,可以根据拼 音检索,也可根据汉字部首检索,当然还有其他检索方式, 帮助我们快速查找需要的信息。这节学习的索引器类似于字 典中的检索,可以根据需要设定不同的检索方式,以快速查 找类或结构的实例。 4.4.2 索引器 57 4.4.2 索引器 索引器用于封装内部集合或数组。 索引器在语法上方便了程序员将类、结构或接口作为数组进 行访问。 要声明类或结构上的索引器,需要使用this关键字。 索引器的定义类似于属性,但其功能与属性并不相同。索引 器提供一种特殊的方法编写get和set访问器。属性可以使用 户像访问字段一样访问对象的数据,索引器可以使用户像访 问数组一样访问类成员。定义索引器的语法如下: 58 索引器是一种特殊的类成员,它能够让类、结构和接口的 实例按照与数组相同的方式进行索引,使程序看起来更为直 观,更容易编写。 1、索引器的定义 C#中的类成员可以是任意类型,包括数组和集合。当一个 类包含了数组和集合成员时,索引器将大大简化对数组或集 合成员的存取操作。 定义索引器的方式与定义属性有些类似,其一般形式如下: 修饰符 数据类型 this索引类型 index get/获得属性的代码 set /设置属性的代码 4.4.2 索引器 59 修饰符包括 public,protected,private,internal,new,virtual,sealed,override, abstract,extern. 数据类型是表示将要存取的数组或集合元素的类型。 索引器类型表示该索引器使用哪一类型的索引来存取数组或 集合元素,可以是整数,可以是字符串;this表示操作本对 象的数组或集合成员,可以简单把它理解成索引器的名字, 因此索引器不能具有用户定义的名称。 例如: 4.4.2 索引器 60 class demo /可容纳100个整数的整数集 private long arr = new long100; /声明索引器 public long thisint index get /检查索引范围 if (index = 100) return 0; else return arrindex; set if (!(index = 100) arrindex = value; 61 接口中的索引器 在接口中也可以声明索引器,接口索引器与类索引器的区别 有两个: 一是接口索引器不使用修饰符; 二是接口索引器只包含访问器get或set,没有实现语句。 访问器的用途是指示索引器是可读写、只读还是只写的,如果是 可读写的,访问器get或set均不能省略;如果只读的,省略set 访问器;如果是只写的,省略get访问器。 62 例如: public interface IAddress string thisint indexget;set; string Addressget;set; string Answer(); 表示所声明的接口IAddress包含3个成员:一个索引器、一 个属性和一个方法,其中,索引器是可读写的。 接口中的索引器 63 例1: public int thisint index / 索引器声明 / get and set accessors 例2: public string thisint i getreturn namei; setnamei=value; 4.4.2 索引器 64 索引器与属性的比较 索引器与属性都是类的成员,语法上非常相似。索引器一般用 在自定义的集合类中,通过使用索引器来操作集合对象就如同 使用数组一样简单;而属性可用于任何自定义类,它增强了类 的字段成员的灵活性。 65 索引器与属

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论