C#类的学习

本文详细介绍了C#中的面向对象特性,包括属性的定义与使用,构造器的规则,静态成员(字段、方法、构造器和属性)的运用,以及继承的概念和规则。同时讲解了protected关键字、密封类和方法,以及virtual、override和new关键字在重写中的作用。此外,还讨论了多态、抽象类和接口的应用,以及继承后构造器的使用方式。
摘要由CSDN通过智能技术生成

封装

这里写的只是视频中的简单操作,更详细的在本质论中

属性

定义与使用

每个成员变量都对应一份属性,用于设置和取得成员变量的值
此外,可以通过只实现set或get其中一个来设置字段的只写和只读

private int _Age;
public int Age
{
	set
	{
		 Console.WriteLine("set被调用");
         Console.WriteLine("value" + value);
         //value是外部给的
	}
	get
	{
		Console.WriteLine("get被调用");
        return 100;
	}
}
//另一种定义方式:自动实现
public string FirstName{get;set;}
public string LastName{get;set;}

使用方式

//使用set
Vector3 v = new Vector3();
v.Age = 200;
//使用get
int t = v.Age;
Console.WriteLine(t);

结果
在这里插入图片描述

使用规范

  1. 字段前附加 “_” 前缀,但不要用下划线
  2. 用名称、名称短语、形容词来命名属性
  3. 优先使用自动实现的属性而不是字段
  4. 如果没有额外的实现逻辑,优先使用自动实现的属性,而不是自己的
  5. 在类中,应使用属性而不是字段,只在属性内部访问属性的支持字段

构造器

定义

class Employee
{
	public Employee(string firstName, string lastName)
	{
		FirstName = firstName;
		LastName = lastName;
	}
	
	public string FirstName{get;set;}
	public string LastName{get;set;}
	//应避免声明时赋值,又在构造器中赋值
	public string Salary{get;set;} = "Not Enough";
	//先执行声明时赋值,再是构造器
}

对象初始化列表:续构造器

在使用构造器时,可以在后面加一对大括号进行复赋值操作

Employee employee1 = new Employee("Inigo","Montoya")
{ Title = "Computer Nerd", Salary = "Not enough"};

静态static

用于定义由多个实例共享的数据,即所以实例共享一个储存位置

静态字段

静态字段作用域是类

class Employee
    {
    	//
        public static int NextId;
        //
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Salary { get; set; } = "Not Enough";
        
        public Employee(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
            //
            Id = NextId;
            NextId++;
            //
        }
    }
    //下面是外部访问方式(两种相同),使用类名Employee
    Employee.NextId = 100000;
    Console.WriteLine($"NextId = {Employee.NextId}");
    Console.WriteLine("NextId = {0}", Employee.NextId);

静态方法

  • 与字段相同,直接使用类名访问静态方法,如Console.ReadLine()
  • this关键字不能在静态方法中使用

静态构造器

对类(不是类的实例)进行初始化
在第一次用到这个类时调用,可以是调用普通构造器时,访问静态方法或字段
静态构造器只能用静态字段,把静态数据初始化为特定的值
尤其是无法通过声明的简单赋值来获得初始值的字段

static Employee()
{
	   Random randomGenerator = new Random();
	   //NextId在上面
	   NextId = randomGenerator.Next(101, 999);
}

静态属性

静态属性几乎比公共静态字段好,毕竟提供了一定的封装

public static int NextId
{
     get
     {
         return _NextId;
     }
     private set
     {
         _NextId = value;
     }
}
public static int _NextId = 42;
//相当于
public static int NextId { get; private set; } = 42;

静态类

  1. 该类无法实例化,且里面的字段和方法都是static
  2. 不可扩展,即不能派生出其他类
using static SimpleMath;
//加了这行后,就不需要使用SimpleMath前缀,可以直接调用内部方法
    public static class SimpleMath
    {
        public static int Max(int[ ] numbers)
        {
            int result;
            result  = numbers[0];
            foreach(int number in numbers)
            {
                if(number>result)
                {
                    result = number;
                }
            }
            return result;
        }
        public static int Min(int[] numbers)
        {
            int result;
            result = numbers[0];
            foreach (int number in numbers)
            {
                if (number < result)
                {
                    result = number;
                }
            }
            return result;
        }
    }
//使用方式
Console.WriteLine($@"Longest argument length = {SimpleMath.Max(numbers)}");
Console.WriteLine($@"Longest argument length = {SimpleMath.Min(numbers)}");

继承

一个类只能继承自一个类,不能多继承,这是与C++的关键区别之一

基类与派生类的互相赋值

  1. 可以把派生类的值直接给基类,称为隐式转换
  2. 基类的值给派生类称为显式转换,有限制,不一定成功

protected关键字

class PdaItem
    {
        public string Name { get; set; }
        public DateTime LastUpdated { get; set; }
    }
class Contact:PdaItem
    {
        public string Address { get; set; }
        public string Phone { get; set; }
    }
static void Main(string[] args)
    {
         Contact contact = new Contact();
         PdaItem item = contact;
         contact = (Contact)item;
     }

密封(sealed)

密封类

使用sealed关键字的类,不能从该类派生

public sealed class CommandLineParser
    {
        //……
    }

密封方法

class A
{
    public virtual void Method()
    {
    }
}
class B : A
{
    public override sealed void Method()
    {
    }
}
//可以继承A进行重写,但不能继承B进行重写
class C : A
{
    public override void Method()
    {
    }
}

基类的重写

virtual、override关键字

virtual在父类中声明,用override在子类中重写
使用时,会调用最新的、最远的重写方法
用override修饰符的方法都会自动成为虚方法,其他派生类可以进一步“特化”其作用
但是,当使用基类实例化基类,而不是用派生类的值赋予基类,那么这个基类使用的方法仍是基类中的,而不是重写后的

class PdaItem
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Salary { get; set; } = "Not Enough";
        public virtual string Name
        {
            get
            {
                return $"{FirstName}{LastName}";
            }
            set
            {
                Console.WriteLine("PdaItem");
                string[] names = value.Split(" ");
                FirstName = names[0];
                LastName = names[1];
            }
        }
    }
class Contact:PdaItem
    {
        public override string Name
        {
            get
            {
                return $"{FirstName}{LastName}";
            }
            set
            {
                Console.WriteLine("Contact");
                string[] names = value.Split(" ");
                FirstName = names[0];
                LastName = names[1];
            }
        }
        public new string FirstName { get; set; }
        public new string LastName { get; set; }
    }
static void Main(string[] args)
        {
            Contact contact = new Contact();
            PdaItem item = new PdaItem();
            //PdaItem item = contact ;
            item.Name = "Inigo Montoya";
            contact.Name = "Inigo Montoya2";
            Console.WriteLine($"{item.FirstName }{item.LastName }");
            Console.WriteLine($"{contact.FirstName }{contact.LastName }");
        }

结果:
在这里插入图片描述
若是用派生类给基类赋值

static void Main(string[] args)
        {
            Contact contact = new Contact();
            //PdaItem item = new PdaItem();
            PdaItem item = contact ;
            item.Name = "Inigo Montoya";
            //contact.Name = "Inigo Montoya2";
            Console.WriteLine($"{item.FirstName }{item.LastName }");
            Console.WriteLine($"{contact.FirstName }{contact.LastName }");
        }

结果:
在这里插入图片描述
注意:不要在编写构造器时使用会影响构造对象的虚方法
假如这个虚方法在当前要实例化的派生类中被重写,就会调用重写后的方法,而在这时候,字段还未完全初始化,那么就有可能发生无法预测的后果

另外:只有实例成员才能使用virtual

new关键字

new关键字实际上不是重写,而是另写一个同名的方法,可以说是用来移除报错的

public class BaseClass
        {
            public void DisplayName()
            {
                Console.WriteLine("BaseClass");
            }
        }
        public class DerivedClass : BaseClass
        {
            public virtual void DisplayName()
            {
                Console.WriteLine("DerivedClass");
            }
        }
        public class SubDerivedClass:DerivedClass
        {
            public override void DisplayName()
            {
                Console.WriteLine("SubDerivedClass");
            }
        }
        public class SuperSubDerivedClass : SubDerivedClass
        {
            public new void DisplayName()
            {
                Console.WriteLine("SuperSubDerivedClass");
            }
        }
        public static void Main()
        {
            SuperSubDerivedClass superSubDerivedClass = new SuperSubDerivedClass();
            SubDerivedClass subDerivedClass = superSubDerivedClass;
            DerivedClass derivedClass = superSubDerivedClass;
            BaseClass baseClass = superSubDerivedClass;

            superSubDerivedClass.DisplayName();
            subDerivedClass.DisplayName();
            derivedClass.DisplayName();
            baseClass.DisplayName();
        }

结果:

在这里插入图片描述

继承后的构造器

实例化派生类时,会先调用基类的构造器,对基类进行初始化,用base指定使用哪个构造器,基类构造器中的参数必须在base后面都写上

  1. 基类无参,派生类有参
class Pdaaitem
        {
            public Pdaaitem()
            {
                //Name = name;
            }
            
            public string Name { get; set; }
        }
        class Contact : Pdaaitem
        {
            public Contact(string name)//:base(name)
            {
                Name = name;
            }
            public new string Name { get; set; }
        }
  1. 基类有参,派生类有参,派生类参数不少于基类,
class Pdaaitem
        {
            public Pdaaitem(string name)
            {
                Name = name;
            }
            
            public string Name { get; set; }
        }
        class Contact : Pdaaitem
        {
        //public Contact(string name,int age):base(name)
            public Contact(string name):base(name)
            {
                Name = name;
            }
            public string Name { get; set; }
        }
  1. 基类无参,派生类无参
class Pdaaitem
        {
            public Pdaaitem()
            {
                //Name = name;
            }
            
            public string Name { get; set; }
        }
        class Contact : Pdaaitem
        {
            public Contact()//:base(name)
            {
                //Name = name;
            }
            public string Name { get; set; }
        }

多态

相同签名的成员在不同的类有不同的实现称为多态性
一个类可以同时继承一个基类和多个接口,基类在前

抽象类

抽象类中定义了派生类应该包含什么,但不包含如何实现,所以无法使用抽象类实例化对象
要从抽象类中派生,必须对抽象方法提供具体的实现

抽象类中的方法可以使用abstract,也可以不用

abstract class Pdaaitem
        {
            public int I { set; get; }
            public abstract void Test();
            public virtual string Name { get; set; }
        }
class Contact : Pdaaitem
        {
            public override  void Test()
            {

            }
            public override string Name
            {
                set
                {
                    Name = "siki";
                }
                get
                {
                    return "siki";
                }
            }

如果不用abstract修饰方法,而是只是抽象类

abstract class Pdaaitem
        {
            public int I { set; get; }
            public void Test()
            {
                Console.WriteLine("Pdaaitem");
            }
            public virtual string Name { get; set; }
        }
class Contact : Pdaaitem
        {
            public new  void Test()
            {
                Console.WriteLine("Contact");
            }
            public override string Name
            {
                set
                {
                    Name = "siki";
                }
                get
                {
                    return "siki";
                }
            }
        }
private static void Main()
        {
        	//下面这一条会报错
            //Pdaaitem pdaaitem2 = new Pdaaitem();
            Pdaaitem pdaaitem = new Contact();
            pdaaitem.Test();
            Contact contact = new Contact();
            contact.Test();
        }

结果:
在这里插入图片描述

接口(interface关键字)

  1. 接口将实现细节和功能分开,用各种派生类中的不同实现来实现多态
  2. 接口不包含任何实现,也就是只有函数头
  3. 接口不能有字段,如果接口要求派生类包含特定数据,会声明属性而不是字段
  4. 接口成员不能有访问修饰符,全部自动定义为public
  5. 接口没有构造器和终结
  6. 接口不能包含静态成员
  7. 接口成员不能用abstract修饰符
  8. 命名规范:用大写字母“I"作为前缀
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值