C# 入门教程(C#语法- 5.自定义类)
graph LR
C[自定义类] --> D[标识符命名规则和约定]
C --> E[字段]
C --> H[属性]
C --> G[构造函数]
C --> F[方法]
C --> K[事件]
C --> N[索引器]
C --> I[内部类和嵌套类]
C --> J[继承和接口]
C --> L[静态成员]
C --> M[综合示例]
标识符命名规则和约定
- 大驼峰和小驼峰 当在C#中使用驼峰命名约定时,有两种常见的方式:大驼峰(PascalCase)和小驼峰(camelCase)。下面是这两种方式的示例:
- 大驼峰(PascalCase):首字母大写,每个单词的首字母也大写。
// 类名
public class PersonInfo
{
// 属性名
public string FullName { get; set; }
// 方法名
public void SayHello()
{
Console.WriteLine("Hello!");
}
}
- 小驼峰(camelCase):首字母小写,后续每个单词的首字母大写。
// 变量名
string firstName = "John";
int myAge = 25;
// 方法名
public void printMessage()
{
Console.WriteLine("This is a message.");
}
无论是大驼峰还是小驼峰,都是为了使代码更加可读和易于理解。
规则
有效标识符必须遵循以下规则:
- 标识符必须以字母或下划线 (_) 开头。
- 标识符可以包含 Unicode 字母字符、十进制数字字符、Unicode 连接字符、Unicode 组合字符或 Unicode 格式字符,有关 Unicode 类别的详细信息,请参阅 Unicode 类别数据库
命名约定
除了规则之外,在 .NET API 中还使用了许多标识符命名约定。 按照约定,C# 程序对类型名称、命名空间和所有公共成员使用 PascalCase。 此外,团队使用从 运行时团队编码风格中吸收的以下约定:
接口名称以大写字母 I 开头。
将 PascalCase 用于类名和方法名称。
将 camelCase 用于方法参数、局部变量和专用字段。
将 PascalCase 用于常量名,包括字段和局部常量。
属性类型以单词 Attribute 结尾。
枚举类型对非标记使用单数名词,对标记使用复数名词。
标识符不应包含两个连续的下划线 (_) 字符。 这些名称保留给编译器生成的标识符。
对变量、方法和类使用有意义的描述性名称。
避免使用单字母名称,但简单循环计数器除外。 请参阅以下部分所述的语法示例的例外。
清晰胜于简洁。。
专用实例字段以下划线(_)开头。
静态字段以 s_ 开头。 请注意,这不是默认的 Visual Studio 行为,也不是框架设计准则的一部分,但在 editorconfig 中可配置。
避免在名称中使用缩写或首字母缩略词,但广为人知和广泛接受的缩写除外。
使用遵循反向域名表示法的有意义的描述性命名空间。
选择表示程序集主要用途的程序集名称。
字段
字段(Fields):用于存储类的数据。字段是类的成员变量,它们可以是任何数据类型,并且可以具有访问修饰符来控制其可见性。
using System;
class Person
{
public string name; // 字段
public void PrintName()
{
Console.WriteLine("My name is " + name);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.name = "Alice";
person.PrintName();
}
}
属性
属性(Properties):用于封装字段,并提供对字段的访问和修改。属性本质上是一对方法(getter和setter),可以在获取或设置属性值时执行自定义逻辑。属性可以具有不同的访问修饰符,以控制对属性的访问级别。
using System;
class Person
{
private string name; // 私有字段
public string Name // 属性
{
get { return name; }
set { name = value; }
}
public void PrintName()
{
Console.WriteLine("My name is " + name);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "Alice"; // 设置属性值
person.PrintName();
}
}
以下是C#中属性和字段的区别对比表格:
属性 (Property) | 字段 (Field) | |
---|---|---|
定义 | 声明为属性,使用 get 和 set 访问器定义 |
声明为字段,在类或结构体中直接声明 |
封装性 | 可以实现隐藏字段的实际实现细节并添加逻辑 | 仅存储数据,没有封装性 |
访问控制 | 可以设置访问级别(公开、私有等) | 默认为私有,可以通过访问修饰符更改 |
兼容性 | 可以轻松修改属性的实现,而不会影响使用者 | 修改字段的实现可能会影响使用者 |
使用 | 使用 obj.PropertyName 访问和赋值 |
使用 obj.FieldName 直接访问和赋值 |
示例 | public int Age { get; set; } |
public int age; |
总结:
- 属性(Property)使用
get
和set
访问器定义,可以实现封装性、访问控制和兼容性,通过obj.PropertyName
访问和赋值。 - 字段(Field)直接在类或结构体中声明,仅用于存储数据,没有封装性,并且可以通过访问修饰符更改访问级别,通过
obj.FieldName
直接访问和赋值。
构造函数
构造函数(Constructors):用于创建类的对象。构造函数在实例化类时被调用,可以接受参数来初始化对象的状态。
using System;
class Person
{
private string name;
public Person(string n) // 构造函数
{
name = n;
}
public void PrintName()
{
Console.WriteLine("My name is " + name);
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person("Alice"); // 实例化对象时调用构造函数
person.PrintName();
}
}
方法
方法(Methods):用于定义类的行为和功能。方法包含一系列语句,可以执行特定的操作,并且可以接受参数和返回值。
using System;
class Calculator
{
public int Add(int a, int b) // 方法
{
return a + b;
}
}
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
int result = calculator.Add(3, 4); // 调用方法
Console.WriteLine("The result is: " + result);
}
}
事件
事件(Events):用于实现发布-订阅模式,允许一个对象通知其他对象发生了某些事情。
using System;
class Button
{
public event Action Click; // 事件
public void OnClick()
{
if (Click != null)
{
Click.Invoke();
}
}
}
class Program
{
static void Main(string[] args)
{
Button button = new Button();
button.Click += () =>
{
Console.WriteLine("Button clicked!");
};
button.OnClick(); // 触发事件
}
}
这段代码是一个简单的示例,演示了如何使用事件和委托来创建一个按钮类。
首先,在代码的开头使用了System命名空间,它包含了许多常用的系统类和方法。
然后定义了一个名为Button的类,其中声明了一个事件Click,该事件使用了Action委托类型。Action委托是一种通用的无返回值委托,可以用来引用一个没有参数和返回值的方法。
在Button类中,还定义了一个名为OnClick的方法。当调用该方法时,它会检查事件Click是否有订阅者(即事件是否为空)。如果有订阅者,就调用Click事件并执行其中的方法。
在Program类的Main方法中,创建了一个Button对象button。接下来,使用lambda表达式创建了一个匿名方法,并将其添加到button的Click事件的订阅列表中。这个匿名方法只是简单地打印出"Button clicked!"的消息。
最后,通过调用button的OnClick方法,手动触发了Click事件。当Click事件被触发时,所有订阅者都会执行相应的方法,从而输出"Button clicked!"的消息。
总结起来,这段代码展示了一个按钮类的基本结构,以及如何使用事件和委托来实现对按钮点击事件的订阅和处理。
索引器
索引器(Indexers):允许对象像数组一样通过索引进行访问。索引器可以通过索引操作符([])来访问。
using System;
class MyArray
{
private object[] data = { 1, 2, 3, 4, 5 };
public object this[int index] // 索引器
{
get { return data[index]; }
set { data[index] = value; }
}
}
class Program
{
static void Main(string[] args)
{
MyArray array = new MyArray();
Console.WriteLine("Element at index 2: " + array[2]); // 使用索引器获取值
array[2] = 10; // 使用索引器设置值
Console.WriteLine("Element at index 2 after modification: " + array[2]);
}
}
内部类和嵌套类
内部类和嵌套类(Inner Classes and Nested Classes):类可以包含其他类,这些类被称为内部类或嵌套类。内部类可以访问包含它们的外部类的成员。
using System;
class OuterClass
{
private string outerName;
public OuterClass(string name)
{
outerName = name;
}
public void PrintOuterName()
{
Console.WriteLine("Outer name: " + outerName);
}
public class InnerClass // 内部类
{
private string innerName;
public InnerClass(string name)
{
innerName = name;
}
public void PrintInnerName()
{
Console.WriteLine("Inner name: " + innerName);
}
}
}
class Program
{
static void Main(string[] args)
{
OuterClass outer = new OuterClass("Outer");
outer.PrintOuterName();
OuterClass.InnerClass inner = new OuterClass.InnerClass("Inner");
inner.PrintInnerName();
}
}
继承和接口实现
继承和接口实现(Inheritance and Interface Implementation):一个类可以继承自另一个类,从而继承其成员和行为。此外,一个类还可以实现一个或多个接口,以定义所需的契约和功能。
using System;
class Animal
{
public virtual void MakeSound() // 虚方法
{
Console.WriteLine("The animal makes a sound.");
}
}
class Dog : Animal
{
public override void MakeSound() // 重写基类方法
{
Console.WriteLine("The dog barks.");
}
}
interface IFlyable
{
void Fly(); // 接口方法
}
class Bird : Animal, IFlyable
{
public override void MakeSound() // 重写基类方法
{
Console.WriteLine("The bird chirps.");
}
public void Fly() // 实现接口方法
{
Console.WriteLine("The bird flies.");
}
}
class Program
{
static void Main(string[] args)
{
Animal animal = new Animal();
animal.MakeSound();
Dog dog = new Dog();
dog.MakeSound();
Bird bird = new Bird();
bird.MakeSound();
bird.Fly();
}
}
静态成员
静态成员(Static Members):静态成员属于类本身,而不是类的实例。静态字段、方法和属性可以在不创建对象的情况下直接访问。
using System;
class MathUtils
{
public static int Add(int a, int b) // 静态方法
{
return a + b;
}
public static int Multiply(int a, int b) // 静态方法
{
return a * b;
}
public static double Pi = 3.14159; // 静态字段
}
class Program
{
static void Main(string[] args)
{
int sum = MathUtils.Add(3, 4); // 使用静态方法
Console.WriteLine("The sum is: " + sum);
int product = MathUtils.Multiply(2, 5); // 使用静态方法
Console.WriteLine("The product is: " + product);
Console.WriteLine("The value of PI is: " + MathUtils.Pi); // 访问静态字段
}
}
以上是每种部分的一个完整可运行示例代码。希望能够帮助你更好地理解类的各个组成部分。如果还有其他问题,请随时提问!
综合示例
classDiagram
class WasteWater {
<<废水类>>
- Type : string 废水类型
- Source : string 废水来源
- IsHarmful : bool 是否有害
+ ProcessedEvent : event EventHandler<EventArgs> 废水处理完成事件
+ OnProcessed() : virtual void 触发废水处理完成事件的方法
+ DisplayInfo() : string 显示废水信息的方法
}
class NuclearWasteWater {
<<核废水类>>
- RadioactiveMaterial : string[] 放射性物质数组
+ DisplayInfo() : string 显示核废水信息的方法
}
class IWaterProcessor {
<<水处理器接口>>
+ ProcessWater(water: WasteWater) : void 处理水的方法
}
class NuclearWasteProcessor {
<<核废水处理器类>>
+ ProcessWater(water: WasteWater) : void
}
class CommonWasteProcessor {
<<普通废水处理器类>>
+ ProcessWater(water: WasteWater) : void
}
class WaterProcessingProgram {
<<主类>>
+ Main(args: string[]) : void 入口函数
+ WasteWater_Processed(sender: object, e: EventArgs) : static void
}
WasteWater <|-- NuclearWasteWater
WaterProcessingProgram --|> WasteWater : 包含
WaterProcessingProgram --|> NuclearWasteWater : 包含
IWaterProcessor <|.. NuclearWasteProcessor : 实现
IWaterProcessor <|.. CommonWasteProcessor : 实现
WaterProcessingProgram ..> IWaterProcessor : 使用
using System;
namespace HelloWorldApplication
{
// 废水类
class WasteWater
{
// 属性: 类型、来源、是否有害
public WasteWater(string type, string source, bool isHarmful)
{
Type = type;
Source = source;
IsHarmful = isHarmful;
}
// 类型
public string Type { get; set; }
// 来源
public string Source { get; set; }
// 是否有害
public bool IsHarmful { get; set; }
// 事件处理器
public event EventHandler<EventArgs> ProcessedEvent;
// 触发废水处理完成事件
protected virtual void OnProcessed()
{
ProcessedEvent?.Invoke(this, EventArgs.Empty);
}
// 显示废水信息
public virtual string DisplayInfo()
{
return $"废水类型: {Type}, 来源: {Source}, 是否有害: {IsHarmful}";
}
// 处理水的方法
public void ProcessWater(IWaterProcessor waterProcessor)
{
Console.WriteLine($"正在处理{Type}。。。");
waterProcessor.ProcessWater(this);
OnProcessed();
}
}
// 核废水类,继承自废水类
class NuclearWasteWater : WasteWater
{
// 放射性物质数组
public string[] RadioactiveMaterial { get; set; }
// 构造方法
public NuclearWasteWater(string type, string source, bool isHarmful, string[] radioactiveMaterial)
: base(type, source, isHarmful)
{
RadioactiveMaterial = radioactiveMaterial;
}
// 显示核废水信息(重写父类方法)
public override string DisplayInfo()
{
string baseInfo = base.DisplayInfo();
string radioactiveMaterial = string.Join(", ", RadioactiveMaterial);
return $"{baseInfo}, 放射性物质: [{radioactiveMaterial}]";
}
}
// 水处理器接口
interface IWaterProcessor
{
// 处理水
void ProcessWater(WasteWater water);
}
// 核废水处理器类,实现水处理器接口
class NuclearWasteProcessor : IWaterProcessor
{
// 处理水的方法
public void ProcessWater(WasteWater water)
{
Console.WriteLine("正在处理核废水。。。");
}
}
// 普通废水处理器类,实现水处理器接口
class CommonWasteProcessor : IWaterProcessor
{
// 处理水的方法
public void ProcessWater(WasteWater water)
{
Console.WriteLine("正在处理普通废水。。。");
}
}
// 主类
class WaterProcessingProgram
{
static void Main(string[] args)
{
// 创建工业废水对象
WasteWater wasteWater = new WasteWater("工业废水", "工厂", false);
wasteWater.ProcessedEvent += WasteWater_Processed; // 订阅事件
Console.WriteLine(wasteWater.DisplayInfo());
// 创建普通废水处理器对象,并处理工业废水
IWaterProcessor commonWaterProcessor = new CommonWasteProcessor();
wasteWater.ProcessWater(commonWaterProcessor);
// 创建放射性物质数组
string[] radioactiveMaterial = { "Uranium-235", "Plutonium-239" };
// 创建核废水对象
NuclearWasteWater nuclearWasteWater = new NuclearWasteWater("核废水", "某本", true, radioactiveMaterial);
nuclearWasteWater.ProcessedEvent += WasteWater_Processed; // 订阅事件
Console.WriteLine(nuclearWasteWater.DisplayInfo());
// 创建核废水处理器对象,并处理核废水
IWaterProcessor nuclearWaterProcessor = new NuclearWasteProcessor();
nuclearWasteWater.ProcessWater(nuclearWaterProcessor);
Console.ReadKey();
}
// 废水处理完成事件的处理方法
static void WasteWater_Processed(object sender, EventArgs e)
{
WasteWater wasteWater = sender as WasteWater;
Console.WriteLine($"{wasteWater.Type}废水处理完成。请进行下一步操作。。。");
}
}
}
小结
C#的自定义类就讲到这里,代码可以自定义,你的人生也可以由你来定义,忽略负面,做一个强大的自己。
大家有任何问题都可以加关注后在评论区留言,或者加客服一对一咨询。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明