C#教程(2)-----对象和类型篇

一:类和结构

类和结构其实就是实现对象的模板,每个对象都有数据和处理数据的方法。

类和结构的不同点:
a、类支持继承,结构不支持继承
b、类是引用类型,存储在堆(heap)上,结构是值类型,存储在栈(stack)上
c、类的关键字(class),结构的关键字(struct)。

示例1:

class PhoneCustomer
{
            public const string DayOfSendingBill = "Monday";
            public int CustomerID;
            public string FirstName;
            public string LastName;
}

两者都是用new关键字创建并对其进行初始化

二:类

类包含成员,成员分为静态成员和实例成员。静态成员属于类,实例成员属于对象。即静态字段的值在每个对象中都是相同的,实例字段每个对象都可以有不同的值。静态成员关联了static修饰符

成员 说明
字段 字段是类的数据成员,它是类型的一个变量,该类型是类的一个成员
常量 常量与类相关。编译器使用真实值代替常量
方法 与特定类相关的函数
属性 可以从客户端访问的函数组
构造函数 实例化对象是自动调用的特殊函数
索引器 允许对象用访问数组的方式访问
运算符 运算符执行的最简单的操作就是执行加法和减法
事件 事件是类成员,在发生某些行为时调用
析构函数 类似于构造函数的语法
类型 类可以包含内部类

1.字段

字段时与类相关的变量。
实例化示例1的对象之后,就可以用如下方法访问:

var customer1 = new PhoneCustomer();
Console.WriteLine(customer1.CustomerID);

使用const声明常量,如果将其声明为public,就可以在类外访问它。
最好不要把字段声明为public。

2.属性

**概念:**他是一个方法或一对方法,在客户端代码看来,他们是一个字段。
例如:

class PhoneCustomer
        {
            private string _firstName;
            public string FirstName
            {
                get { return _firstName; }
                set { _firstName = value; }
            }
        }

包括get和set两个访问器,用来获取和设置字段的值

a、自动实现的属性

如果属性的set和get访问器中没有任何的逻辑,就可以使用自动实现的属性。这种书行贿自动实现后被成员变量。
例如:

public int Age { get; set; } 

不需要声明私有字段。编译器就会自动创建它。自动实现的属性可以使用属性初始化器来初始化

public int Age { get; set; } = 42;

b、属性的访问修饰符

C#允许给属性的get和set访问器设置不同的访问修饰符,所以可以有共有的get访问器和私有的set访问器。有卒于控制属性的设置方式和时间;在get和set访问器中,必须有一个具备属性的访问级别;
例如:

public string FirstName
            {
                get { return _firstName; }
                private set { _firstName = value; }
            }
public int Age { get;private set; } = 42;

3.方法

a、方法的声明

形式:

修饰符 返回值类型 方法名(参数列表)
{
	方法体
}

例如:

private string getName(string id)
{
	return Name;
}

b、 表达式体方法

如果方法的实现只有一条语句,C#6提供一个简化方法:表达式体方法
舍弃了花括号和return关键字,使用=>区分左边声明和右边实现代码
例如:private string getName(string id)=>Name;

c、调用方法

实例:

using System;
using System.Threading;

namespace ConsoleApp2
{
    class Math
    {
        public int value{get; set;}
        public int getSquare() => value * value;
        public static int getSquareOf(int x) => x * x;
        public static double GetPi() => 3.14159;

        static void Main(string[] args)
        {
            
            Console.WriteLine("Pi is "+Math.GetPi());
            Console.WriteLine($"Pi is {Math.getSquareOf(5)}");

            var math = new Math();//实例化一个对象

            math.value = 30;
            Console.WriteLine($"value field of math variable contains{math.value}");
            Console.WriteLine($"square if 30 is {math.getSquare()}");
            
            Thread.Sleep(5000);//睡眠5000毫秒,也就是5秒
        }
    }
}

结果:
在这里插入图片描述
理解上述实例就能轻松掌握调通方法的技巧。

d、方法的重载

定义:方法名相同,但方法的参数个数和数据类型不同。
在这里插入图片描述
(上述例子只为重载而重载,没有任何实际意义)

e、可选参数

假如一个方法有两个参数,其中有一个参数调用时可能会用到,也可能时默认值。这时候我们就可以将其设置为可选参数。例:

public static int getSquareOf(int x,int y = 42) => x * x * y * y;

我们调用的方法有下列两种;

Math.getSquareOf(5);
或
Math.getSquareOf(5,1);

注意:可选参数可以有有多个,可选参数必须放在参数的最后面。
例如:

public static void  getSquareOf(int x, int y = 5, int z = 4)
        {
            Console.WriteLine($"x is {x}");
            Console.WriteLine($"y is {y}");
            Console.WriteLine($"z is {z}");
        }

调用示范:

Math.getSquareOf(1,z:3);
Math.getSquareOf(1,y:2);

f、个数可变参数

除了可选参数外,还有一种方法可以实现参数个数可变的方法;

实例:(注意getSquareOf方法)

using System;
using System.Threading;

namespace ConsoleApp2
{
    class Math
    {
        public int value{get; set;}
        public int getSquare() => value * value;
        public static void  getSquareOf(params int[] x)
        {
            foreach (int temp in x)
            {
                Console.Write(temp+" ");
            }
            Console.WriteLine();//换行
        }
        public static double GetPi() => 3.14159;

        static void Main(string[] args)
        {

            Math.getSquareOf(1);
            Math.getSquareOf(1,2,3,4);
            Math.getSquareOf(1,2,3,4,5,6,7,8,9,10);

            
            Thread.Sleep(5000);//睡眠5000毫秒,也就是5秒
        }
    }
}

结果:
在这里插入图片描述
如果想将不同类型的参数传给方法,可以将int数组换成obiect数组。如果params关键字与其他参数一起使用,需要将其放在最后,并只能使用一次。

4.构造方法

构造函数名必须与类名相同,但是没有返回值。
例如:

class Math
    {
        public Math()
        {
        }
     }

如果开发者没有给类提供构造函数,那么编译器就会生成一个极其简单的构造函数用来初始化工作。

a、在构造函数中调用其它构造函数

有类如下👇

class Math
    {
        int x;
        int y;
        
        public Math(int _x)
        {
            x = _x;
            y = 2;
        }
        public Math(int _x,int _y)
        {
            x = _x;
            y = _y;
        }
        //etc

咋一看这个代码,有两个构造函数,函数体大致相同,只有y变量操作不同,如果操作再多一点,就会造成代码重复,啥玩应 。那么,他来了!!!!!!(构造函数初始化器
👏👏👏

class Math
    {
        int x;
        int y;
        
        public Math(int _x):this( _x, 2)
        {
        }
        public Math(int _x,int _y)
        {
            x = _x;
            y = _y;
        }
        //etc

是不是感觉变好看了呢!this关键字只调用参数最匹配的那个构造函数

C#构造函数初始化器可以包含对同一个类的构造函数的调用(上述语法),也可以对积累的构造函数进行调用(使用相同的语法,但应该将this换成base),初始化器不能有多个调用

b、静态构造函数

可以编写无参的静态构造函数是C#的特征之一。这种构造函数只执行一次,通常在第一次实用类之前执行。

同学A:为啥要写静态构造函数?”
“老师:不知道”
老师:”类有一些静态字段或属性,需要在使用前进行初始化。

注意:静态构造函数没有访问修饰符,其他C#代码从不显示调用它,.NET运行库在加载类是调用它,且只能访问类的静态成员
使用范例:

using System;
using System.Drawing;
using System.Threading;

namespace ConsoleApp2
{
    public static class UserPreferences
    {
        public static Color BackColor { get; }
        static UserPreferences()
        {
            DateTime now = DateTime.Now;
            if (now.DayOfWeek == DayOfWeek.Saturday || now.DayOfWeek == DayOfWeek.Sunday)
            {
                BackColor = Color.Green;
            }
            else
            {
                BackColor = Color.Red;
            }
        }
        static void Main(string[] args)
        {

            Console.WriteLine($"User-preferences:BackColor is : {UserPreferences.BackColor}");

            
            Thread.Sleep(5000);//睡眠5000毫秒,也就是5秒
        }
    }
}

如果理解了上述代码,那么恭喜你这节毕业了。👏👏👏👏

5.只读字段

只读字段用readonly修饰符声明,只能在构造函数中分配值。与const不同,编译器通过const,用他的值取代变量。与const相反,只读字段可以作为实例成员,这是需要加上static。

比如说一个文档编辑程序,需要限制文档最大打开数。现在顾客升级该程序后需要修改文档最大打开数。显然不能再源代码中对其进行硬编码,而是需要一个只读字段来表示,每次打开程序时读取。

public static class UserPreferences
    {
        private static readonly uint max_Count;
        static UserPreferences()
        {
            max_Count = DoSometh();
        }
        //etc

只读属性
在属性定义中省略set访问器就可以创建只读属性。
用readonly修饰符声明字段只允许在构造函数中初始化属性的值。

6.匿名类型

var关键字用于表示隐式类型化的变量,new和var关键字一起使用时可以创建匿名类型,匿名类型是一个继承自object且没有名称的类。该类的定义从初始化器中推断,类似于隐式类型化的变量。

var caption = new
            {
                firstName = "James",
                middleName = "T",
                lastName = "Kirk"
            };

在写另一个匿名类型

var doctor = new
            {
                firstName = "w",
                middleName = "j",
                lastName = "s"
            };

那么就可以说doctor和caption类型相同,当类型相同时,可以设置caption = doctor。
当设置的值来自于一个有存在对象可以这样写:

var doctor = new
            {
                caption.firstName,
                caption.middleName,
                caption.lastName
            };

7.枚举

枚举时一个值类型,包含一组命名的常量。示例如下:👇

    public enum color
        {
            red,
            green,
            blue
        }

可以声明枚举类型变量:

color c1 = color.red;

默认情况下,enum的类型是int。可以改为其他整数类型(byte,short、int、带符号的long和无符号的变量)。命名常量的值从0开始递增。也可以改为其他值

public enum color:short
        {
            red = 1,
            green = 2,
            blue = 3
        }

使用强制类型转换可以把数字转换为枚举值,或者把枚举值转换为数字。

color c2 = (color)2;
short = number = (short)c2;

8.部分类

partial关键字允许把类、结构、方法或接口放在多个文件中。简单的说就是把类、结构、方法或接口拆开放在不同的源文件下。
partial用法:将其放在class、struct或interface关键字前面。
部分类可以包含部分方法
例如:

public void MethodOne()
{
	ApartialMethod();
}
public partial void ApartialMethod()
{
}

9.扩展方法

扩展方法是给对象添加功能的一个选项,在不能使用继承时,可以使用。
例如:(扩展string)

public static int GetCountOfWord(this string s) => s.Split().Length;

使用this关键字和第一个参数来扩展字符串,这个关键字定义了要扩展的类型

10.Object类

Tpstring()方法: 转换为字符串。
GetHashCode()方法: 如果对象放在名为映射(散列表或字典)的结构中,就可以使用这个方法。
GetType方法: 返回一个从System.Object派生的类的一个实例。
MemberwiseClone方法: 复制对象并返回一个对副本的引用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章