C#语法基础详解(万字总结)-类型

时间:2024-07-19 07:31:54

非嵌套的类修饰符publicinternalabstractsealedstaticunsafepartial

字段

class User{
    string name;
    public int Age =10;
}

字段可以用以下修饰符进行修饰

  • 静态修饰符:static
  • 访问权限修饰符:public, internal,private,protected
  • 继承修饰符:new
  • 不安全代码修饰符:unsafe
  • 只读修饰符:readonly
  • 线程访问修饰符:volatile

**readonly只读修饰符:**只能在声明或构造器中赋值

重载

void Foo(int x){...}
void Foo(double x){...}
void Foo(int x,double y){...}
void Foo(string x,int y){...}

若返回类型不同则不是重载,类型中不可以使用。

按值传递和按引用传递

void Foo(ref int x)//或Foo(out int x) 
void Foo(out int x) //error compile-time
void Foo(int x)

局部方法

局部方法不能使用static修饰,如果父方法是静态的那么局部方法也是静态的

void WriteCubes(){
    Console.WriteLine(Cube(3));
    int Cube (int value)=>value*value*value;
}

重载构造器

public class Person{
    public int Age ;
    public string Name;
    public Person(int age){Age=age;}
    public Person (int Age,string name):this(age){Name=name;}
}

当构造器调用另一个构造器的时候,被调用的构造器先执行

解构器

class DeconTest
{
    private readonly int a1 = 10, a2 = 10, a3 = 10;
    public DeconTest(int a1, int a2, int a3)
    {
        this.a1 = a1;
        this.a2 = a2;
        this.a3 = a3;
    }
    public void Deconstruct(out int A1, out int A2, out int A3)
    {
        A1 = a1;
        A2 = a2;
        A3 = a3;
    }
      public void Deconstruct(out int A1, out int A2)
    {
        A1 = a1;
        A2 = a2;

    }
}
DeconTest deconTest = new DeconTest(1, 2, 3);
var (b1, b2) = deconTest;
var (c1, c2, c3) = deconTest;
Console.WriteLine($"{b1} - {b2} - {c1} - {c2} - {c3}");

解构器是为了更好的拿到类中的属性

对象初始化器

namespace Init;
class InitTest
{
    public int A1 = 1, A2 = 2;

    public InitTest()
    {
    }
    public InitTest(int a1)
    {
        A1 = a1;
    }

}
InitTest initTest = new InitTest() { A1 = 10, A2 = 5 };
InitTest initTest2 = new InitTest(11) { A2 = 5 };
Console.WriteLine($"{initTest.A1}-{initTest.A2}-{initTest2.A1}-{initTest2.A2}");

属性

属性有get和set方法

public class Stock{
    // The private "backing" field// The public property
    decimal currentPrice;
    public decimal CurrentPrice{
        get{return currentPrice;}
        set{currentPrice=value;}
    }
}

只读属性

public class Stock{
    // The private "backing" field// The public property
    decimal currentPrice;
    public decimal CurrentPrice{
        get{return currentPrice;}      
    }
}
表达式属性(只读属性才可以)
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName => $"{FirstName} {LastName}";
}
自动属性
public class Stock{
    public decimal CurrentPrice{get;set;}
}
属性初始化器
public int Maximum{get;}=999;
public currentPrice{get;set;}=123;

索引器

namespace Index;
public class IndexerTest
{
    string[] words = "czm is best".Split();
    public string this[int wordsNum]
    {
        get { return words[wordsNum]; }
        set { words[wordsNum] = value; }
    }
}
IndexerTest indexerTest = new IndexerTest();
Console.WriteLine(indexerTest[0]);
indexerTest[2] = "jamin";
Console.WriteLine(indexerTest[2]);

静态构造器

静态构造器只执行一次,不是每个实例执行一次。

nameof运算符

nameof运算符返回任意符号的字符串的名称(类型、成员、变量等)

string name =nameof(StringBuilder.Length)//name is Length

继承

类型转换和引用转换

as运算符
Animal animal = new Dog();
Dog dog = animal as Dog;
if (dog != null)
{
    dog.Bark();
}

使用as运算符若转换失败返回Null而不报错

is运算符
Animal animal = new Dog();
if (dog is animal)
{
    dog.Bark();
}

is运算符检验转换是否成功

is与模式变量
if(a is Animal animal){Console.WriteLine(s.name)}

虚函数成员

提供特定实现的子类可以重写标识为virtual的函数。

public class Animal 
{
    public virtual void MakeSound()
    {
        Console.WriteLine("This animal makes a sound");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("The dog barks");
    }
}

public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("The cat meows");
    }
}

抽象类和抽象成员

声明为抽象的类不能够实例化。

抽象成员不提供默认的实现,其实现必须由子类提供。除非子类也为抽象类。

new和重写

New

public class BaseClass
{
   public void MyMethod()
   {
       Console.WriteLine("BaseClass.MyMethod()");
   }
}

public class DerivedClass : BaseClass
{
   new public void MyMethod()
   {
       Console.WriteLine("DerivedClass.MyMethod()");
   }
}
BaseClass obj = new DerivedClass();
obj.MyMethod();  // 输出 "BaseClass.MyMethod()"

重写

public class BaseClass
{
   public virtual void MyMethod()
   {
       Console.WriteLine("BaseClass.MyMethod()");
   }
}

public class DerivedClass : BaseClass
{
   public override void MyMethod()
   {
       Console.WriteLine("DerivedClass.MyMethod()");
   }
}
BaseClass obj = new DerivedClass();
obj.MyMethod();  // 输出 "DerivedClass.MyMethod()"

base关键字

Public class House :Asset{
    public override decimal Liability =>base.Liability +Mortgage;
}

通过base访问基类的属性。

构造器与继承

public class BaseClass
{
    public BaseClass()
    {
        Console.WriteLine("Base class constructor called.");
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass() : base()
    {
        Console.WriteLine("Derived class constructor called.");
    }
}
class Inherit
{
    public Inherit(int a)
    {
        Console.WriteLine("base" + a);
    }
}
class SubInherit : Inherit
{
    public SubInherit() : base(10)
    {
        Console.WriteLine("Sub");
    }
}

若基类中没有无参构造函数则派生类必须带有一个显式调用基类的一个带参数的构造函数。

object类型

装箱和拆箱

装箱:将值类型实例转换为引用类型实例

int x=9;
object obj =x;

拆箱:将引用类型转换为值类型(需要显式的类型转换)

int y =(int)obj;

装箱是把值类型的实例复制到新对象中,而拆箱是把对象的内容复制回值类型的实例中。下面的示例修改了i的值,但并不会改变它先前装箱时复制的值:

int i= 3;
object boxed =i;
i =5;
Console.WriteLine(boxed);//3

GetType和typeof

在类型实例上调用GetType方法(运行时)

在类型名称上使用typeof运算符(编译时)

public class Point {public int x,y;}
class Test{
    static void Main(){
        Point p=new Point();
        Console.WriteLine(p.GetType().Name);
        Console.WriteLine(typeof(Point).Name);
        Console.WriteLine(typeof(p.x.GetType().FullName);
    }
}

结构体

值类型 派生自System.ValueType

using System;
using System.Text;
     
struct Books
{
   public string title;
   public string author;
   public string subject;
   public int book_id;
};  

public class testStructure
{
   public static void Main(string[] args)
   {

      Books Book1;        /* 声明 Book1,类型为 Books */
      Books Book2;        /* 声明 Book2,类型为 Books */

      /* book 1 详述 */
      Book1.title = "C Programming";
      Book1.author = "Nuha Ali";
      Book1.subject = "C Programming Tutorial";
      Book1.book_id = 6495407;   
       
      /* 打印 Book1 信息 */
      Console.WriteLine( "Book 1 title : {0}", Book1.title);
      Console.WriteLine("Book 1 author : {0}", Book1.author);
      Console.WriteLine("Book 1 subject : {0}", Book1.subject);
      Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);
   }
}

友元程序集

接口

接口不提供成员的实现,因为它所有的成员都是隐式抽象的。

接口成员总是隐式public访问权限

接口实现类是internal访问权限但仍可以通过接口作为public去访问成员

public interface Ienumerator{
    bool MoveNext();
    object Current{get;}
    void Reset();
}
internal class countdown :Ienumerator{
    int count =11;
    public bool MoveNext=>count-- >0;
    public object Current =>count;
    public void Reset(){throw new Exception();}
}
Ienumerator e=new Countdown();
Console.Write(e.Current);

扩展接口

接口可以从其他接口派生

public interface Iundoable{void Undo();}
public interface IRedoable : Iundoable{void Redo();}

Iredoable继承了Iundoable接口的所有成员。

显式接口实现

interface I1{void Foo();}
interface I2{int Foo();}

public class Widget:I1,I2{
    public void Foo(){
        Console.WriteLine("I1.Foo");
    }
    int I2.Foo(){
        Console.WriteLine("I2.Foo");
        return 27;
    }
}

虚方法实现接口

默认情况下,隐式实现的接口成员是密封的。为了重写,必须在基类中将其标识为virtual或者abstract。

虚函数常常被用在模板方法设计模式中,在这个模式中,一个父类定义了一个方法来完成一个特定的工作流程,而将这个工作流程中的某些步骤延迟到其子类中实现。这些可以被子类定制的步骤通常被定义为虚函数。

public interface IUndoable{void Undo();}
public class TextBox:IUndoable{
    public virtual void Undo()=>Console.WriteLine("TextBox.Undo");
}
public class RichTextBox:TextBox{
    public override void Undo()=>Console.WriteLine("RichTextBox.Undo");
}

调用时不管从基类还是接口中调用接口成员都是 子类的实现 “RichTextBox.Undo”

枚举类型

public enum BorderSide{Left,Right,Top,Bottom}//默认为0,1,2,3
public enum BorderSide{Left=1,Right=5,Top=10,Bottom=12}//指定值

当指定部分枚举的值时,会在有值的枚举值上递增。

枚举类型转换

int i=(int) BorderSide.Left;
BorderSide side =(BorderSide) i;

标志枚举类型

BorderSide leftRight=BorderSide.Left | BorderSide.Right;
if((leftRight & BorderSide.Left)!=0)
    Console.WriteLine("包含 Left");

**注:**枚举可以与整形参与运算,但两个枚举不可以做加法。

嵌套类型

public class TopLevel
{
    public class nested { }
    public enum Color { red, green, blue }
}
TopLevel.Color color = TopLevel.Color.red;
  • 可以访问包含它的外层类型中的私有成员,以及外层类所能够访问的所有内容

    public class TopLevel
    {	
        static int x;
    	class Nested{
    		static void Foo(){ Console.WriteLine(TopLevel.x);}
        }
    }
    
  • 可以在声明上使用所有的访问权限修饰符,而不限于public和internal.

public class TopLevel
{
	protected class Nested {}
}
public class SubTopLevel :TopLevelstatic{
    void Foo(){ new TopLevel.Nested();}
}
  • 嵌套类型的默认可访问性是private而不是internal.
  • 从外层类以外访问嵌套类型,需要使用外层类名称进行限定(就像访问静态成员一样)。
public class TopLevel
{
    public class nested { }
}

class Test{
    TopLevel.Nested n;
}

泛型

public class Stack<T>
{
    int position;
    T[]data = new T[100];
    public void Push(T obj)=> data[position++]= obj;
    public TPop()=>data[--position];
}
var stack =new Stack<int>();
stack.Push(5);
stack.Push(10);
int x =stack.Pop();//x is 10
int y =stack.Pop();//y is 5

泛型方法

static void Swap<T>(ref T a,ref T b){
    T temp =a;
    a=b;
    b=temp;
}
int x=5;
int y=10;
Swap(ref x,ref y);
//或者Swap<int>(ref x,ref y)显式指出泛型的类型

声明类型参数

public struct Nullable<T>{
    public T Value{get;}
}

泛型或方法可以有多个参数,例如:

class Dictionary<TKey,TValue>{...}

可以用以下方式实例化:

Dictionary<int,string>myDic =new Dictionary<int,string>();

typeof 和未绑定泛型类型

    Type t = typeof(Dictionary<,>);
    Console.WriteLine(t.Name);

泛型的约束与继承

在下面的例子中GenericClass<T,U>的T要求派生自(或者本身就是)SomeClass并且实现 Interface1;要求U提供无参数构造器。

class GenericClass<T,U> where T : SpmeClass,Interface1 where U:new()

继承

class Stack<T>{...}
class SpecialStack<T>:Stack<T>{...}

静态数据

class Bob<T>{public static int Count;}
class Test{
static void Main(){ 			
    Console.WriteLine(++Bob<int>.Count); //1
    Console.WriteLine++Bob<int>.Count);//2
    Console.WriteLine++Bob<string>.Count);//1
    Console.WriteLine++Bob<obect>.Count);//1
}

协变与逆变