在好例子网,分享、交流、成长!
<<

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)。下面是这两种方式的示例:
  1. 大驼峰(PascalCase):首字母大写,每个单词的首字母也大写。
// 类名
public class PersonInfo
{
    // 属性名
    public string FullName { get; set; }
    
    // 方法名
    public void SayHello()
    {
        Console.WriteLine("Hello!");
    }
}
  1. 小驼峰(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)
定义 声明为属性,使用 getset 访问器定义 声明为字段,在类或结构体中直接声明
封装性 可以实现隐藏字段的实际实现细节并添加逻辑 仅存储数据,没有封装性
访问控制 可以设置访问级别(公开、私有等) 默认为私有,可以通过访问修饰符更改
兼容性 可以轻松修改属性的实现,而不会影响使用者 修改字段的实现可能会影响使用者
使用 使用 obj.PropertyName 访问和赋值 使用 obj.FieldName 直接访问和赋值
示例 public int Age { get; set; } public int age;

总结:

  • 属性(Property)使用 getset 访问器定义,可以实现封装性、访问控制和兼容性,通过 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小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

报警