1.结构和类
结构和类很相似,都是具备方法和数据的集合,但是区别也很明显,两者的区别在于存储区域的,结构存储于栈中是值类型,而类存储于堆中,是引用类型
2.类
类中有许多内容,他们之间又有一定的关联性,所以学起来不是很容易,最好是先能理解简单的内容,后面再串起来
2.1静态类成员
静态成员属于类,实例成员属于对象,所有实例成员都能访问到这个共享的静态成员。修饰符采用static
2.2只读类成员
只读成员和常量两者的概念一致,但是常量需要在编译时就能确定,而只读成员的初始化需要在构造函数中进行初始化。static+readOnly声明一个静态只读成员,集合两种修饰符的特性
2.3属性
一般程序员都能接触到这个概念,给你的数据成员访问提供一个拦截访问的地方
属性中需要注意的是属性的访问修饰符,给get和set提供访问级别,但有个前提就是属性的被访问级别足够低(public),这样get和set只能继承访问级别和设置在这个级别之上的访问修饰符
2.4方法
方法中一般的概念就是重载,局部函数等之类,可以描述比较多的内容就在于函数的参数问题中。
- 方法重载,方法重载在于函数的签名(不包括返回值和函数修饰符)
- 参数:
- 可选参数,设置了默认值就是可以充当可选参数,但是要放在参数的后面
- 命名参数,指定参数来赋值,可以不依据参数的数据
- 参数数组,接受多个不定长的参数,多余的数据会被传递至声明了params的特定类型的参数数组中
- 参数:值参数和引用参数。当方法调用时,函数会有自己的执行栈,对于实参传入的参数会进行复制赋予形参,这就导致了引用实参传入在方法内对 引用区域的操作能够作用于方法外
3.ref,out,in修饰符
这三个修饰符能够提供给方法的参数和返回之中。
3.1ref修饰符
ref修饰的参数在方法执行过程中充当参数的别名,也就是同在方法外部访问这个变量一致(同时也说明了使用这个参数传入的不能是直接的值类型,而是需要变量)。
对于这个ref特殊一点的就是对于引用类型。没有ref的引用类型,在内部修改了引用参数在栈中的地址是无法影响到外部的变量,而ref引用的则可以。对于引用区域的修改两者的表现是一致的,下面是代码示例
void AsParameter(MyClass f1)
{
f1.Val = 50;
Console.WriteLine($"非ref修改后:{f1.Val}");
f1 = new MyClass();
Console.WriteLine($"非ref创建新对象后:{f1.Val}");
}
void RefAsParameter(ref MyClass f2)
{
f2.Val = 50;
Console.WriteLine($"ref修改后:{f2.Val}");
f2 = new MyClass();
Console.WriteLine($"ref创建新对象后:{f2.Val}");
}
MyClass a1 = new MyClass();
MyClass a2 = new MyClass();
AsParameter(a1);
Console.WriteLine($"外部访问非ref修改:{a1.Val}");
RefAsParameter(ref a2);
Console.WriteLine($"外部访问ref修改:{a2.Val}");
class MyClass
{
public int Val = 20;
}
3.2out修饰符
out修饰符表现和ref是一致的(对于方法重载来说,声明ref和声明out方法不能当做重载方法) ,而out和ref区别首先是在语义上,out是为了满足想要传递多个不同类型的数据作为返回值而存在,而且out不需要在变量传递前进行初始化,但是需要在方法返回前进行初始化
3.3in修饰符
in修饰过的参数不能被修改,而对于引用类型数据来说,他所指向的内容区域可以修改,而引用本身不能被修改
void inAsParameter(in MyClass f3,in int a)
{
//修改值类型
//a = 1;
Console.WriteLine($"{a}");
f3.Val = 50;
Console.WriteLine($"引用类型的修改{f3.Val}");
}
MyClass a3 = new MyClass();
inAsParameter(a3, 1);
2.5构造函数
构造函数一般来说在各大语言中都有描述,所以这不描述这个概念,而是描述静态构造函数。静态构造函数是为了初始化静态数据成员,因为静态数据成员不属于任何一个成员,所以提供了一个构造函数用于它的初始化, 里面不能访问到this实例,同时在调用完这个构造函数后会调用类的普通构造函数
这样也有弊端就是每一轮都调用这个静态初始化构造函数初始化一遍,这可能不是我们想要的结果
RandomNumverClass a = new RandomNumverClass();
a.Val = 10;
Console.WriteLine($"Val:{a.Val}");
RandomNumverClass b = new RandomNumverClass();
Console.WriteLine($"Val:{b.Val}");
Console.WriteLine($"random value:{a.GetRandomNumber}");
class RandomNumverClass
{
private static Random RandomKey;
public int Val;
static RandomNumverClass()
{
RandomKey = new Random();
}
public RandomNumverClass()
{
Val = 50;
}
public int GetRandomNumber()
{
return RandomKey.Next();
}
}
3.结构
对于一个新内容,我们关注的是为什么要使用,如何使用两个部分,而其他内容不是关注的重点可以放一放。
3.1为什么要使用结构
结构的存储为栈中,而类存储在堆中,编译器对堆操作的开销比对栈要高。而且类的功能丰富,对于那些不需要使用这些功能的操作,显然是不必要的
3.2如何使用?
struct虽然是值类型,但是初始化使用的是new,同时也具备构造函数(没有析构函数),又因为他是值类型所以变量之间的赋值是变量拷贝操作。
构造函数的存在就是为了初始化,struct存在预定义的无参构造函数,用于将数据初始化为他们的默认值。定义了带参的构造函数,就可以在new中去初始化结构成员。构造函数可以设置为静态这里的表现和类的静态构造函数是一致的。
using System.Reflection.Metadata.Ecma335;
Simple ss = new Simple();
Simple aa = ss;
aa.X = 1;
Console.WriteLine($"ss:{ss.X}");
Console.WriteLine($"ss:{aa.X}");
struct Simple
{
public int X;
public int Y;
}
struct CSimple
{
public int X;
public int Y;
}
4.枚举类型
4.1枚举类型的初始化
枚举类型支持设置底层类型和显示值,同时有自己的一套值初始化规则,支持的底层类型如下
对于枚举类型其他特性现在没有涉及就不过多涉及。