Notas de estudo em C# – uso de estudo pessoal<1>

Notas de estudo em C#



Capítulo 1 Os fundamentos mais suaves do C#

Seção 1 Classes e Namespaces

As referências a bibliotecas de classes são a base física para a utilização de espaços de nomes.Projectos de diferentes tipos de tecnologia utilizarão diferentes bibliotecas de classes por defeito.

  • Referência de DLL, referência de caixa preta, sem código-fonte;
  • Referência do projeto, referência de caixa branca, código fonte;

Parte 1 Namespace NameSpace

O objetivo dos namespaces é fornecer uma maneira de um conjunto de nomes ser separado de outros nomes, de modo que o nome de uma classe declarada em um namespace não entre em conflito com o nome da mesma classe declarada em outro namespace.
O método de declaração é o seguinte:

namespace namespace_name
{
    
    
   // 代码声明
}

A palavra-chave using indica que o programa usa o nome no namespace fornecido. Por exemplo, usando a classe Console no namespace System, você pode escrever assim:

Console.WriteLine();

Se a palavra-chave using não for usada, o nome completo poderá ser escrito:

System.Console.WriteLine();

Namespaces podem ser aninhados, use o operador ponto (.) para acessar membros de namespaces aninhados;

Parte 2 Aula

Dependência: A relação de acoplamento entre classes ou objetos deve ser buscada"Alta coesão, baixo acoplamento"as regras.

O que é uma aula:

  • Classe Classe é um modelo de coisas do mundo real;
  • A relação entre classes e objetos
    • Quando é chamado de "objeto" e quando é chamado de "instância": Objetos e instâncias são a mesma coisa.InstanciarA entidade na memória obtida posteriormente; mas algumas classes não podem ser instanciadas; instanciação é criar um objeto de acordo com uma determinada classe, que é instanciação. Abstratamente falando, significa possessão pelo diabo. O diabo é virtual. Após a posse, ele se torna uma entidade, que é instanciação; usonovoOs operadores criam instâncias de classes;
    • A relação entre variáveis ​​de referência e instâncias: O conceito de variáveis ​​de referência é muito importante. Usando o método de variáveis ​​de referência, você pode operar continuamente a mesma instância, conforme mostrado abaixo;
Form myForm;
myForm = new From();
myForm2 = myForm;  // 二者引用的是同一个实例,操作同一个实例;
  • Os três principais membros da classe
    • PropriedadePropriedadeDedicado ao armazenamento de dados, os dados podem ser combinados para representar o status atual da classe ou objeto, também chamado de “campo”;
    • MétodoMétodo: representa uma classe ou objetoo que pode ser feito, é uma função, é um algoritmo;
    • Evento: um mecanismo para classes ou objetos notificarem outras classes ou objetos, mantido por C#
  • Membros estáticos e membros de instância de uma classe: membros estáticos (estáticos) representam semanticamente que são "membros de uma classe", enquanto membros de instância (não estáticos) representam semanticamente que são "membros de um objeto" e não pertencem a uma determinada classe;
    • Sobre vinculação Vinculação: refere-se ao compilador associando um membro a uma classe ou objeto;

Seção 2 Elementos Básicos

Os elementos básicos que compõem a linguagem C#

  • Palavra-chavePalavra-chave
  • Operador: símbolo utilizado para expressar ideias operacionais;
  • Identificador: O nome deve começar com um caractere ou sublinhado. C Sharp diferencia maiúsculas de minúsculas. Os nomes das variáveis ​​usam maiúsculas e minúsculas (semelhante a myForm) e os nomes dos métodos usam o método Pascal (a primeira letra de todas as palavras é universidade).
  • Pontuação
  • texto
  • Comentários e espaço em branco

Os primeiros cinco itens são chamados coletivamente de tokens, que são úteis para o compilador.


Seção 3 Tipos de dados

Parte 1 O que é um tipo?

  • Tipo Tipo, também chamado de tipo de dados Tipo de dados,é um conjunto de valores com as mesmas propriedades,Está equipado com uma série de operações específicas para este tipo de valor.
  • É o modelo quando os dados são armazenados na memória;
  • Se uma memória pequena acomodar dados de grande tamanho, a precisão será perdida e ocorrerão erros;
  • Memória grande para acomodar dados de tamanho pequeno levará ao desperdício;
  • Os tipos de dados das linguagens de programação não são exatamente iguais aos tipos de dados;

Parte 2 O papel dos tipos em Dó sustenido

As informações contidas em um tipo C# consistem em:

  • A quantidade de espaço de memória necessária para armazenar este tipo de variável;
  • A faixa de valores máximo e mínimo que este tipo de valor pode representar
  • Os membros contidos neste tipo (como métodos, propriedades, eventos, etc.);
  • De qual classe base esse tipo deriva?
  • Quando o programa está em execução, onde na memória estão alocadas variáveis ​​desse tipo?
    • Introdução à pilha
    • Estouro de pilha
    • Introdução ao Heap
    • Use o Monitor de Desempenho para visualizar o uso de memória heap de um processo
    • Sobre vazamentos de memória
  • Operações (operações) permitidas por este tipo
Tipo Faixa Tamanho
byte -128 a 127 Inteiro assinado de 8 bits
byte 0 a 255 Inteiro não assinado de 8 bits
curto -32.768 a 32.767 Inteiro assinado de 16 bits
ucurto 0 a 65.535 Inteiro não assinado de 16 bits
interno -2.147.483.648 a 2.147.483.647 Inteiro assinado de 32 bits
unint 0 a 4.294.967.295 Inteiro não assinado de 32 bits
longo -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 Inteiro assinado de 64 bits
cabeça 0 a 18.446.744.073.709.551.615 Inteiro não assinado de 64 bits
Tipo/palavra-chave C# Alcance aproximado Precisão Tamanho Tipo .NET
flutuador ±1,5 x 10^−45 a ±3,4 x 10^38 ~6-9 dígitos 4 bytes Sistema.Single
dobro ±5,0 × 10^−324 a ±1,7 × 10^308 ~15-17 dígitos 8 bytes Sistema.Duplo
decimal ±1,0 x 10^-28 a ±7,9228 x 10^28 28-29 dígitos 16 bytes Sistema.Decimal

O programa está no período estático ao escrever código e compilar, e o período dinâmico ocorre durante a execução e depuração.

Stack é usado para chamadas de métodos; Heap é usado para armazenar objetos;
geralmente a pilha é menor e o heap é maior;
o programa aloca objetos no heap e não os recicla após o uso, o que desperdiça memória e também é chamado de vazamento de memória .;
Não existe reciclagem manual em C Sharp, existe um mecanismo automático de reciclagem;

// 例子:
class BadGuy
{
    
    
    public void BadMethod()
    {
    
    
        int x = 100;
        this.BadMethod();
        // 只递不归,会导致栈爆掉 Stack Overflow
    }
}

// int 有7为总共2097152字节,下面的例子会导致栈爆掉,编译无问题但会 Stack Overflow
unsafe
{
    
     
	int* p = stackalloc int[9999999];  
}

Processo de processo: a instância do programa após a execução. Após a execução, há um ID do programa, chamado PID.
Use perfmon para abrir o monitor de desempenho.

Tipos de dados na Parte 3 C Sharp

Cinco tipos principais de dados em C Sharp

  • Classes como Windows, Form, Console, String (mais utilizadas para iniciantes)
  • Estruturas como Int32, Int64, Single, Double (mais utilizadas para iniciantes)
  • Enumerações como HorizontalAlignment, Visibility
  • InterfaceInterface
  • Delegados

As classes são declaradas usando a palavra-chave class;

As estruturas são declaradas usando a palavra-chave struct;

Tipo de enumeração, dada uma coleção, o usuário só pode selecionar um valor da coleção, e não pode selecionar um valor arbitrariamente, ou seja, os dados dentro são todos opções predefinidas.O tipo declarado usando palavras-chave é um tipo de enumeração, como o enumseguinte exemplo;

namespace System.Windows.Forms
{
    
    
	public enum FormWindowState
	{
    
    
		Normal = 0,
		Minimized = 1,
		Maximized = 2,
	}
}

Esses tipos de dados constituem o sistema de tipos de dados C#, conforme mostrado abaixo:
Pedigree derivado do tipo C Sharp
classes, interfaces e delegados são classificados como tipos de referência; estruturas e enumerações são classificadas como tipos de valor; todos os tipos usam o tipo Object como tipo base;

O primeiro grupo corresponde a tipos de referência. Objeto e string são tipos de dados reais e possuem classes correspondentes. A classe, interface e delegado com linhas horizontais para baixo não são tipos de dados específicos, mas referem-se a três palavras-chave para definir seus próprios tipos de dados; O segundo
grupo group corresponde ao tipo de valor, as palavras-chave azuis acima da linha horizontal, struct abaixo da linha horizontal definem a estrutura e enum define a enumeração; o
verdadeiro e o falso no terceiro grupo são valores do tipo booleano; void significa que a função não precisa retornar um valor. null significa que o valor na variável de referência está vazio e não faz referência a nenhuma instância; var e dynamic são usados ​​para declarar variáveis; as palavras azuis no meio indicam que todos
são tipos de dados prontos, e esses tipos de dados são muito comumente usados ​​e foram absorvidos como palavras-chave pelo C#. E esses tipos de dados são tipos de dados básicos, ou seja, outros tipos de dados são compostos desses tipos de dados básicos;

Seção 4 Variáveis, Objetos e Memória

No sistema de tipos da linguagem C#, variáveis ​​de tipos de referência e tipos de valor são armazenadas de forma diferente na memória e possuem características próprias. Se os dois não forem diferenciados, é provável que ocorram erros;

Parte 1 Variáveis

o que é uma variável

  • Superficialmente, isto é, a partir do contexto do código C#, o objetivo das variáveis ​​é armazenar dados;
int x = 100
x =100;
// 表面上就是将标准整数的值 100 通过等号赋值给 x;
// 实际上,x 就是一个标签,标签对应内存中的地址,100 这个值就存在内存中的这个地址中;
// x 是一个整数类型,int32 指的就是 32 个比特位,4 个字节存储这个值,也就是 int 类
// 型的值才能存入这个地址,内存只给分配 4 个字节,内存空间只能存相同或较小的值,后者会造成浪费;
  • Na verdade,Variáveis ​​representam locais de armazenamento, e cada variável possui um tipo para determinar quais valores podem ser armazenados na variável;
    • O nome da variável representa (corresponde) ao local de armazenamento do valor da variável na memória;
    • O tipo de variável informa ao sistema de computador que esta memória é usada para salvar o valor da variável. Se o valor usado para salvar puder ser armazenado nesta memória, está tudo bem. Se não puder ser carregado nesta memória, o compilador reportará um erro;
  • Existem 7 variáveis ​​em C# ("variáveis" no sentido estrito, geralmente referindo-se a variáveis ​​locais )
    • variável estática
    • Variáveis ​​de instância (variáveis ​​de membro, campos)
    • elementos da matriz
    • parâmetro de valor
    • Parâmetros de referência
    • Parâmetros de saída
    • Variáveis ​​locais: variáveis ​​declaradas no corpo do método (corpo da função)

As definições de escrita e uso das 7 variáveis ​​acima no programa

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student();
            student.Age = -1; // 字段裸露在外容易不小心被赋予一个不合理的值

        }
    }

    class Student
    {
    
    
        // 静态成员变量, 隶属于这个类,不属于这个类的实例,字段裸露在外容易不小心被赋予一个不合理的值
        public static int Amount;

        // 字段,属性的雏形,
        public int Age;
        public string Name;

        // 数组类型
        int[] arrays = new int[100];
        // 声明了一个长度为100的整型数组,一个数占4个字节,这个数组也就是400字节的长度

        // 值参数,例如: double a, double b
        public double Add(double a, double b)
        {
    
     
            // 局部变量 例如 result 声明在 Add 函数体当中,
            // 那么 result 就是函数体 Add 的局部变量
            double result = a + b;
            return result;
        }

        // 引用参数变量,在参数前加上 ref,例如: ref double a
        public double Add(ref double a, double b)
        {
    
    
            return a + b;
        }

        // 输出参数变量,在参数前加上 out,例如: out double a
        public double Add(out double a, double b)
        {
    
    
            return a + b;
        }
    }
}

Parte 2 Como declarar variáveis

int a; // 告诉编译器这个参数是存在的,简单的声明变量
a = 100;
int b;
b = 200
int c = a + b;

O formato correto para declarar variáveis ​​é o seguinte: opt significa opcional

有效的修饰符组合(opt)     变量类型     变量名(必须是个名词)     初始化器(opt)
例如声明类:
class Student
{
	public static int Amount = 0; // public static 就是有效的修饰符组合,如果是 public private static 就是无效的修饰符组合
	// int 是变量类型;
	// Amount 就是变量名;
	// 后面的等号和一个值就是初始化器; 
}

Definição de variável:
Variável: Uma área de memória que começa no endereço de memória correspondente ao nome da variável e tem o comprimento do espaço de armazenamento exigido pelo seu tipo de dados.

Parte 3 Variáveis ​​de tipo de valor e memória

A menor unidade de memória é um bit. Oito bits constituem um byte. Os dados são acessados ​​na memória do computador usando bytes como unidade básica. O computador prepara um número exclusivo para cada byte, e o endereço de memória refere-se ao número do byte no computador.

A área laranja na figura abaixo é a área de memória ocupada pelo sistema operacional, e o lado direito é a área de memória livre;
Insira a descrição da imagem aqui
por exemplo

byte b;

A área amarela é ocupada por outros programas, e 10000015 está apenas vago, então a variável b é dada;
Insira a descrição da imagem aqui

byte b;
b = 100;

A representação binária de 100 é 1100100, que possui apenas sete dígitos. A diferença entre o bit mais alto e o bit mais alto é 0. Ele é armazenado na memória da seguinte forma: Se uma
Insira a descrição da imagem aqui
variável com sinal for usada, o bit mais alto será usado como o bit mais alto. bit de sinal, e os dígitos restantes são usados ​​para armazenar dados.Se o valor for um número negativo, cada um Todos os bits são invertidos bit a bit e 1 é adicionado a partir do final;

Variáveis ​​​​de tipos de valor não possuem instâncias. As chamadas instâncias e variáveis ​​​​são combinadas em uma.

Parte 4 Variáveis ​​de tipo de referência e instâncias de memória de referência e memória

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student stu;
        }
    }

    class Student
    {
    
    
        // ID 与 Score 为值类型的变量
        uint ID;
        ushort Score;
    }
}

As áreas laranja e amarela na figura abaixo são ocupadas por outros programas. Os tipos de valor alocam memória de acordo com o tamanho de referência real, mas os tipos de referência não.
Insira a descrição da imagem aqui
A instância de Student está na memória, uint tem 4 bytes, ushort tem 2 bytes. Não está diretamente dividido em 6 bytes na memória. O computador vê que é um tipo de referência e está diretamente dividido em quatro bytes, 32 bits. Esses locais são todos escovados para 0. , indicando que nenhuma instância é referenciada.
Insira a descrição da imagem aqui

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student stu;
            stu = new Student();  // 后面半句表示在堆内存里创建 Student 实例
        }
    }

    class Student
    {
    
    
        // ID 与 Score 为值类型的变量
        uint ID;
        ushort Score;
    }
}

Após alocar a instância, salve o endereço da memória heap na variável stu. Para criar uma instância no heap, você também precisa encontrar memória livre e alocar espaço. Um campo ID ocupa quatro bytes e o outro campo Score ocupa dois bytes. São necessários seis bytes no total, então seis bytes são alocados para a instância na área livre, os primeiros quatro são para uint e os dois últimos são para ucurto.
Insira a descrição da imagem aqui
O endereço alocado 30000001 é convertido em binário: 1,11001001,11000011,10000001.
Os primeiros oito dígitos são 10000001,
seguidos por 11000011
e, em seguida , 11001001.
O dígito restante é 1 e o bit mais alto é preenchido com 0, ou seja, 00000001.
Esses quatro conjuntos de valores são armazenados na memória de acordo com os princípios alto e baixo.
Insira a descrição da imagem aqui
O valor armazenado na variável de referência é o valor do endereço da memória heap onde a instância está localizada. O valor armazenado no variável de referência é o endereço da instância na memória heap, que determina o relacionamento de referência.
A relação entre variáveis ​​​​de tipo de referência e instâncias: Os dados armazenados nas variáveis ​​​​de tipo de referência são o endereço de memória do objeto.

Parte 5 Outros

  • Variáveis ​​locais alocam memória na pilha;
  • Variáveis ​​de instância, ou seja, campos, alocarão memória no heap junto com os campos;
  • O valor padrão de uma variável. Uma vez que a variável é alocada na memória, o bloco de memória é 0 quando não é atribuído um valor. No entanto, as variáveis ​​locais devem receber um valor para passar na compilação;
  • Constante, uma quantidade cujo valor não pode ser alterado, semelhante ao final em Java;
  • Encaixotamento e desembalagem

Seção 5 Definição, chamada e depuração de métodos

Parte 1 Método

  • O antecessor do método Method é a função function na linguagem C/C++
  • Método é um conceito na categoria orientada a objetos e ainda se torna uma função em linguagens não orientadas a objetos;
  • Os métodos são sempre membros de uma classe ou estrutura. As funções em C# não podem ser independentes de uma classe (ou estrutura). Elas são chamadas de métodos apenas quando são membros de uma classe (ou estrutura);
  • Método é um dos membros mais básicos de uma classe (ou estrutura). Existem apenas dois membros mais básicos: campos e métodos (variáveis ​​de membro e funções de membro). A essência é composta de dados + algoritmo; métodos representam classes (ou estruturas). ).o que pode ser feito;

Por que você precisa de métodos e funções ao escrever um programa:

  • Ocultar lógica complexa
  • Divida grandes algoritmos em pequenos algoritmos
  • Reuso

Parte 2 Declaração e invocação de método

  • Em C#, a declaração e a definição de métodos não são separadas.
  • Parâmetro Nome completo do parâmetro Parâmetro formal Parâmetro formal, referido como parâmetro formal
  • A declaração de um método deve ter um cabeçalho de método (atributos opcionais, combinações de modificadores válidos, tipo de valor de retorno, nome do método {frase verbal}, lista de parâmetros de tipo opcional {somente para genéricos}, seguido por parâmetros formais entre parênteses), lista de restrições opcionais no tipo parâmetros) e corpo do método (um bloco de instrução ou ponto e vírgula);
  • A nomenclatura de métodos precisa ser específica para cada caso, e a nomenclatura Pascal precisa usar um verbo ou frase verbal como nome.
  • Ao chamar um método, siga o nome do método com um par de parênteses e escreva os parâmetros necessários dentro dos parênteses. Esses parênteses não podem ser omitidos. O que está escrito entre parênteses são os parâmetros reais, chamados de parâmetros reais Argumento, que pode ser entendido como As condições reais ao chamar o método;
  • A lista de argumentos ao chamar o método deve corresponder à lista de parâmetros quando o método é definido, os valores e variáveis ​​precisam corresponder e o número e o tipo devem corresponder;

Parte 3 Construtor/Construtor

Construtor

  • Construtor é um dos membros do tipo
  • O construtor estreito refere-se ao "construtor de instância" que constrói a estrutura interna da instância na memória;
namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student(); // 这个后面Student后面的括号就是在调用构造器
            Console.WriteLine(student.ID); // 运行之后会有一个值,见下图,表明默认构造器起作用了
        }
    }

	// 当声明一个类,又没有准备构造器,编译器会准备一个默认的构造器
    class Student
    {
    
    
        public int ID;
        public string Name;
    }
}

Insira a descrição da imagem aqui

Se estiver usando um construtor personalizado:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student();
            Console.WriteLine(student.ID);
        }
    }

    class Student
    {
    
    
        // 自定义的,不带参数的构造器
        public Student()
        {
    
    
            this.ID = 1;
            this.Name = "No Name";
        }
        public int ID;
        public string Name;
    }
}

Insira a descrição da imagem aqui
Para atribuir um valor a uma variável durante a inicialização

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student(initID: 12345, initName: "Hello World");
            Console.WriteLine(student.ID);
            Console.WriteLine(student.Name);
        }
    }

    class Student
    {
    
    
        // 自定义的构造器
        public Student(int initID, string initName)
        {
    
    
            this.ID = initID;
            this.Name = initName;
        }
        public int ID;
        public string Name;
    }
}

Os resultados dos dois construtores são diferentes:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student(initID: 12345, initName: "Hello World");
            Console.WriteLine(student.ID);
            Console.WriteLine(student.Name);
            Console.WriteLine("========================");
            Student student1 = new Student();
            Console.WriteLine(student1.ID);
            Console.WriteLine(student1.Name);
        }
    }

    class Student
    {
    
    
        // 自定义的构造器
        public Student(int initID, string initName)
        {
    
    
            this.ID = initID;
            this.Name = initName;
        }

        public Student()
        {
    
    
            this.ID = 1;
            this.Name = "No Name";
        }

        public int ID;
        public string Name;
    }
}

Insira a descrição da imagem aqui
Pessoalmente, sinto que o uso disso é muito semelhante ao uso de self em Python, e o construtor também é semelhante à parte de inicialização de uma classe em Python;

Parte 4 Sobrecarga de métodos

Quando os nomes de dois métodos são exatamente iguais, as assinaturas dos métodos não podem ser iguais.

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Console.WriteLine("Hello");
            Console.WriteLine(100);
            Console.WriteLine(200L);
            Console.WriteLine(300D);
        }
    }

}

Insira a descrição da imagem aqui
Você pode ver que Console.WirteLineeste método possui 17 sobrecargas para garantir que diferentes dados de entrada possam ser impressos na interface da linha de comando.Esta é uma experiência simples e uma compreensão simples da sobrecarga;

O que é sobrecarga de método: Os nomes dos métodos de uma classe podem ser exatamente os mesmos, mas as assinaturas dos métodos não podem ser exatamente as mesmas.

  • As assinaturas dos métodos não podem ser iguais. São compostas pelo número de parâmetros de método e tipo e pelo tipo e tipo (valor, referência ou saída) de cada um de seus parâmetros formais (em ordem da esquerda para a direita). As assinaturas dos métodos são diferentes. Contém valor de retorno;
  • A assinatura do construtor de instância consiste no tipo e tipo (valor, referência ou saída) de cada um de seus parâmetros formais (em ordem da esquerda para a direita);
  • Tomada de decisão de sobrecarga (qual sobrecarga chamar): usada para selecionar o melhor membro de função a ser chamado, dado um conjunto de membros de função candidatos na lista de parâmetros;

O exemplo a seguir mostra como declarar um método com sobrecarga:

class Calculator
{
    
    
    public int Add(int a, int b)
    {
    
     
        return a + b;
    }

    public int Add<T>(int a, int b)
    {
    
    
        T t; // 类型形参,未来可能会有这个类型参与到方法中
        return a + b;
    }

    public int Add(ref int a, int b)
    {
    
    
        return a + b;
    }

    public int Add(int a, int b, int c) 
    {
    
    
        return a + b + c;
    }

    public double Add(double a, double b)
    {
    
    
        return a + b;
    }
}

O exemplo a seguir explica a resolução de sobrecarga:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Calculator c = new Calculator();
            int x = c.Add(100, 100);
            Console.WriteLine(x);

            double y = c.Add(100D, 1200D);
            Console.WriteLine(y);
        }
    }

    class Calculator
    {
    
    
        public int Add(int a, int b)
        {
    
     
            return a + b;
        }

        public int Add<T>(int a, int b)
        {
    
    
            T t; // 类型形参,未来可能会有这个类型参与到方法中
            return a + b;
        }

        public int Add(ref int a, int b)
        {
    
    
            return a + b;
        }

        public int Add(int a, int b, int c) 
        {
    
    
            return a + b + c;
        }

        public double Add(double a, double b)
        {
    
    
            return a + b;
        }
    }
}

Insira a descrição da imagem aqui

Parte 5 Como depurar métodos

  • Definir ponto de interrupçãoBreakpoint
  • Observe a pilha de chamadas quando um método é chamado
  • Step-in, Step-over, Step-out
  • Observe os valores e alterações das variáveis ​​locais
Ponto de interrupção

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Quebre o ponto onde necessário, que é um ponto vermelho na área branca. A linha de código correspondente aparecerá em uma área vermelha. Após a execução, quando o programa for executado na área do ponto de interrupção, o programa fará uma pausa e colocará o mouse no área desejada. Acima da variável a ser visualizada, é exibido o valor atual da variável. No Visual Studio, o canto inferior esquerdo exibirá os valores de todas as variáveis ​​no ponto de interrupção. Este é o papel dos pontos de interrupção.
Você pode ver a função atualmente chamada através da pilha de chamadas mostrada na figura abaixo: o nível superior é a função atual, o próximo é a função que chama essa função e assim por diante.
Insira a descrição da imagem aqui

Step-in, Step-over, Step-out

Insira a descrição da imagem aqui
Na parte da barra de ferramentas do Visual Studio, da esquerda para a direita estão Step-into (tecla F11), Step-over, Step-out

Step-in significa entrar no código e observar as etapas de execução do programa passo a passo. É semelhante a observar o processo. O processo de observar o processo começa no ponto de interrupção e você pode observar os valores das variáveis ​​passo a passo.
Step-over representa o método específico de ignorar o método e olha diretamente para o resultado;
Step-out representa o local onde o ponto de interrupção é chamado de volta;


Seção 6 Explicação detalhada dos operadores (princípios e uso do operador)

Parte 1 Visão Geral do Operador

Todos os operadores em C#

  • A imagem acima mostra todos os operadores da linguagem C#. Cada operador possui uma operação única;
  • Operador Operador também é chamado de operador;
  • Os operadores são usados ​​para operar dados, e os dados operados pelo operador são chamados de operando Operando;
  • Na figura acima, a prioridade da tabela diminui de cima para baixo, ou seja, quanto maior a prioridade, maior a prioridade. Exceto a última linha, o conteúdo da linha tem a mesma prioridade. Quando esses operadores são combinados , de As operações são executadas de cima para baixo. Exceto a última linha, os operadores na mesma linha são normalmente operados da esquerda para a direita (a expressão à esquerda é avaliada primeiro e depois a expressão à direita é avaliada). O oposto é verdadeiro para a última linha. Os operadores na mesma linha são operados da direita para Operar sequencialmente da esquerda para a direita (primeiro avalie a expressão à direita, depois a expressão à esquerda);
  • Ao usar operadores, você precisa prestar atenção ao problema da promoção numérica.

A natureza dos operadores C#

  • A essência de um operador é uma "abreviação" para uma função (ou seja, algoritmo);
  • Um operador não pode ser separado do tipo de dados ao qual está associado;
    • Pode-se dizer que um operador é uma abreviação de um conjunto de algoritmos básicos associados a um tipo de dados fixo.Um exemplo é mostrado na figura abaixo;

Insira a descrição da imagem aqui
Crie um exemplo simples como mostrado abaixo:
Insira a descrição da imagem aqui
crie uma Pessoa, use a função GetMarry para adicionar continuamente dois parâmetros formais e, finalmente, retorne uma lista do tipo Pessoa; você pode ver que onze linhas de resultados são geradas; substitua GetMarry pelo operador If a palavra-chave "+" está no formato, o método original desaparecerá. Substitua o acima por person1 + person2, e o resultado após a operação será consistente com o resultado do método original;

Insira a descrição da imagem aqui
Este exemplo mostra que os operadores em C# são abreviações para métodos e funções.

Parte 2 Prioridade e ordem das operações

  • Ao realizar cálculos, você pode aumentar a prioridade de execução da expressão adicionando parênteses, e os parênteses podem ser aninhados e o cálculo mais interno é calculado primeiro.
  • A ordem de funcionamento dos operadores com a mesma prioridade, exceto para os operadores com funções de atribuição, os operadores com a mesma prioridade são operados da esquerda para a direita.
  • Todos os operadores com funções de atribuição operam da direita para a esquerda. Os exemplos são os seguintes;
int x;
x = 3 + 4 + 5; // = 是赋值操作符,具有赋值功能的,先计算右侧部分的算式,
			   // 右侧部分的算式由左向右计算,最终将值赋值给 x;
  • Nas linguagens de computador, não existe uma "lei associativa" para operações de mesma prioridade em linguagens de computador;

Há um par de colchetes angulares após a classe, indicando que a classe é uma classe genérica. Uma classe genérica não é uma classe completa e precisa ser combinada com outras classes para se tornar uma classe completa;

Parte 3 Exemplo de Operador

A palavra-chave var está relacionada a variáveis ​​e declara variáveis ​​digitadas implicitamente.

int x; // 显式,告诉编译器这个变量的数据类型
var y; // 隐式,类型暂时不知道,当赋值的时候确定数据类型,也就是编译器有自动类型推导;

O papel do novo operador:

  • Crie uma instância de um tipo na memória
  • e imediatamente chama o construtor de instância desta instância
new Form(); // 就在内存中创建了这个实例,调用了这个实例默认的实例构造器
//===================================
// 将实例的内存地址赋值给变量,就可以通过变量访问这个实例,通常使用这种方法创建实例;
Form myForm = new Form(); 
myForm.Text = "Hello";
myForm.ShowDialog();
//===================================
// 除了调用实例构造器(),还可以调用实例的初始化器{},初始化器还可以初始化多个属性
Form myForm = new Form() {
    
    Text = "Hello", FormBorderStyle = FormBorderStyle.SizableToolWindow}; 
myForm.ShowDialog();
//===================================
// 为匿名类型创建
Form myForm = new Form(){
    
    Text = "Hello"}; // 针对非匿名类型
var person = new {
    
    Name = "Mr.OK", Age = 34}; // 匿名类型创建实例,使用 var 自动推断类型
// var + new 操作符的组合使用,为匿名类型创建对象,并且用隐式类型变量引用实例;

O novo operador é poderoso e não pode ser usado indiscriminadamente. Use injeção de dependência para reduzir o acoplamento ao escrever grandes projetos;
A nova palavra-chave é versátil. Além dos operadores, existem outros usos e não é um operador.
Conforme mostrado abaixo, você pode ver que existem duas linhas de Sou um estudante, porque CsStudent herda da classe pai Student , ou seja, o método Report da classe pai é herdado;
Insira a descrição da imagem aqui
conforme mostrado na figura, new é um modificador neste momento, não um operador. É a ocultação do método da classe pai pela subclasse (raro)
Insira a descrição da imagem aqui

O papel dos operadores verificados e não verificados

  • e verificar se um valor estourou na memória;
  • A palavra-chave Checked é usada para informar ao compilador para verificar se há estouro;
  • A palavra-chave unchecked é usada para informar ao compilador que não há necessidade de verificar se há overflow;
    Insira a descrição da imagem aqui
    defina a variável O overflow é capturado;
    Insira a descrição da imagem aqui
    unchecked é usado aqui sem verificar se há overflow. Você pode ver que depois de x+1, todos os dígitos são aumentados em 1, então o valor se torna 0, que é overflow; o método não verificado é usado por padrão na linguagem C#.
    Os dois usos acima são usados ​​como operadores, e o outro uso é contextual. Conforme mostrado na figura abaixo, usando o método verificado, o bloco de instrução interno detectará se há um estouro interno. O uso de desmarcar é semelhante:
    Insira a descrição da imagem aqui
    operador delegado _
    Geralmente usado como delegado em C#, esse uso é relativamente raro;
    use o operador delegado para declarar métodos anônimos;
    Insira a descrição da imagem aqui
    se você não deseja que o método seja chamado pelo mundo externo e chame-o apenas uma vez, use métodos anônimos;
    Insira a descrição da imagem aqui
    agora expressões lambda geralmente são usados ​​​​para expressar o tipo de dados. Pode ser omitido, conforme mostrado na figura abaixo: o compilador corresponderá automaticamente ao tipo de dados.
    Insira a descrição da imagem aqui

operador sizeof

  • Obter tamanho
  • Obtenha o tamanho de um objeto em bytes na memória;
  • Por padrão, apenas o número de bytes ocupados por instâncias de tipos de dados básicos na memória pode ser obtido.Exceto string e objeto, apenas o número de bytes ocupados por instâncias de tipos de dados estruturais na memória pode ser obtido;
  • Por padrão, sizeof pode ser usado para obter o número de bytes ocupados por uma instância de um tipo de estrutura personalizada na memória, mas precisa ser colocado em um contexto inseguro.

-> operador
As operações de ponteiro só podem operar em tipos de estrutura, não em tipos de referência;
Insira a descrição da imagem aqui
os objetos podem ser acessados ​​por meio de ponteiros, mas só podem ser usados ​​em situações inseguras;

(T)x elenco
Conversão de tipo:

  • Conversão de tipo implícita
    • Conversão sem perda de precisão;
    • Conversão de subclasse para classe pai;
    • Embalagem;
  • conversão de tipo explícita
    • Conversões que podem perder precisão (ou até causar erros), ou seja, conversão;
    • Desembalagem;
    • Use a classe secreta;
    • Método ToString e método Parse/TryParse de cada tipo de dados
  • Operador de conversão de tipo personalizado

O que é conversão de tipo?Veja o exemplo a seguir:
Insira a descrição da imagem aqui
O método Console.ReadLine() retorna um tipo String e eu insiro dois números e espero calcular a soma dos dois números, mas a saída atual é uma combinação de duas strings.
Insira a descrição da imagem aqui
Convert é usado aqui para conversão de tipo de dados, o que ilustra a importância da conversão de tipo de dados; a
introdução formal começa abaixo:

Conversão implícita de tipo Conversão
sem perda de precisão ----------------------
Conversão implícita de tipo sem perda de precisão
A figura acima mostra a conversão implícita de tipo sem perda de precisão, pois o tipo int possui 4 bytes , o tipo longo possui 8 bytes, que podem ser totalmente instalados,
a figura abaixo mostra a conversão numérica implícita sem perder a precisão, ou seja, a precisão será perdida ao converter da direita para a esquerda na figura abaixo;
Insira a descrição da imagem aqui

Conversão de subclasse para classe pai--------------------------
Segue um exemplo:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Teacher t = new Teacher();
            Human h = t;
            t.Teach(); // 可以看到 Teach 方法
            h.Think(); // 看不到 Teach 方法
            // 当试图用一个引用变量去访问所引用实例的成员的时候,
            //只能访问这个变量的类型所具有的成员,而不是这个变量所引用的实例的类型;
            // h 类型为 Human,有两个方法,没有Teach,所以看不到 Teach;
            // 这就是由子类向父类的隐式类型转换;
        }
    }

    class Animal
    {
    
    
        public void Eat()
        {
    
    
            Console.WriteLine("Eating");
        }
    }

    class Human : Animal
    {
    
    
        public void Think()
        {
    
    
            Console.WriteLine("Who I am?");
        }
    }

    class Teacher : Human
    {
    
    
        public void Teach()
        {
    
    
            Console.WriteLine("I teach programming");
        }
    }
}

Conversão de tipo explícito
Por que conversão de tipo explícito?
Como a conversão explícita de tipo pode levar à perda de precisão ou à ocorrência de erros, isto é semelhante à fuga de responsabilidade do compilador.O escritor sabe que a precisão pode ser perdida, mas também deve converter o tipo;

Cast, ou seja, o método (T)x, o seguinte é um exemplo para ilustrar: A
Insira a descrição da imagem aqui
figura acima mostra que quando um dado de 32 bits é colocado em um espaço de 16 bits, apenas o 1 de 16 bits superior pode ser descartado , então é 0 ;
A figura abaixo mostra uma tabela de todas as conversões numéricas explícitas.
Insira a descrição da imagem aqui
Você também precisa prestar atenção aos problemas de sinal ao converter. O bit mais alto de 1 em um tipo de dados assinado é usado para expressar números negativos. Ao converter para um valor sem sinal, o 1 no bit mais alto do bit de sinal será considerado como um valor numérico.

Algumas conversões de tipos de dados não podem ser convertidas usando o formulário Cast, portanto, você precisa usar classes de ferramentas para concluir a conversão.
Classe de ferramenta de conversão: pode converter quase qualquer tipo de dados no tipo de dados desejado;
o método Parse só pode analisar tipos de string com o formato correto. Se a string de entrada não estiver em conformidade com o formato, um erro será relatado;

double x = double.Parse(Console.ReadLine()); 
int y = int.Parse(Console.ReadLine());

Também fornece outro método, tryParse, que retorna Ture de acordo com o tipo;

Insira a descrição da imagem aqui
O princípio de funcionamento por trás do operador de conversão de tipo explícito é mostrado na figura acima, e a conversão de tipo implícita é mostrada na figura abaixo. Os
Insira a descrição da imagem aqui
resultados finais da saída são todos 10.

Operador de mudança >> <<

O operador de deslocamento refere-se a uma certa quantidade de deslocamento dos dados binários na memória para a esquerda ou direita. O exemplo é o seguinte: o valor binário de 7 é 111. Ao deslocar para a esquerda, você pode ver que quando há sem overflow, , mudar uma posição para a esquerda é equivalente a multiplicar por dois. Se ocorrer overflow, no contexto não verificado, causará estouro de dados, mas nenhum erro será relatado. Se estiver no contexto verificado, uma exceção Overflow irá ser recebido.
Insira a descrição da imagem aqui
A imagem abaixo mostra um deslocamento para a direita, também no contexto desmarcado. Nenhum erro será relatado, mas irá transbordar, então os dados estarão incorretos.
Insira a descrição da imagem aqui
Se for um número negativo, qual número deve ser adicionado ao mover o bit mais alto para a direita:
Ao deslocar para a esquerda, seja um número positivo ou negativo, o bit mais alto é preenchido com 0; ao deslocar para a direita, se o número for positivo, o bit mais alto é preenchido com 0, se for um número negativo, o bit mais alto é preenchido com 1

Os resultados de todos os operadores relacionais são verdadeiros ou falsos;

O operador de verificação de tipo é como
Insira a descrição da imagem aqui
pode ser visto na figura acima. O tipo de dados é determinado por is. Se esta classe for derivada de outra classe, então também pode ser determinado que o tipo da primeira é o tipo do pai da última aula.
O uso de as é semelhante: se A for o tipo de dados de B, forneça o endereço de A a C, caso contrário, forneça o valor nulo a C;
Deve-se notar aqui que o uso de como aqui é inconsistente com o uso de como em python.Amigos que transferiram para python devem prestar atenção! ! !

tipo anulável

int? x = null;
Nullable<int> y = null;

Operador condicional?:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int x = 80;
            string str = string.Empty;
            if (x >= 60)
            {
    
    
                str = "Pass";
            }
            else 
            {
    
    
                str = "Failed";    
            }
            Console.WriteLine(str);
        }
    }
}

Você pode ver que o ramo if else ocupa a maior parte do espaço. O mesmo método pode ser alcançado usando o método a seguir.

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int x = 80;
            string str = string.Empty;
            str = (x >= 60) ? "Pass" : "Failed";
            Console.WriteLine(str);
        }
    }
}

Seção 7 Explicação detalhada de expressões e declarações (a ser adicionada - 20230823)

O conteúdo das declarações é muito amplo e muito importante porque constituem o corpo principal do programa;

Parte 1 Visão geral de várias expressões

Classificação de expressões em linguagem C#

Declaração da Parte 2 (a ser adicionada)

Parte 3 Explicação detalhada das declarações

  • declaração
    • declaração rotulada declaração de rótulo
    • declaração-declaração declaração declaração
    • instrução incorporada Instrução incorporada
      O que é uma instrução incorporada? Vamos primeiro examinar a instrução de seleção mais comum, que é a instrução de julgamento. A instrução if é a instrução de seleção mais típica. Vamos tomar isso como um exemplo para apresentar o que é uma instrução incorporada .
namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            bool result = 5 > 3;
            if (result)
                Console.WriteLine("Hello World"); // 嵌套在其他语句中的语句就是嵌入式语句

        }
    }
}

Insira a descrição da imagem aqui
Como você pode ver, a parte selecionada em azul é uma instrução de seleção, que está aninhada na instrução de seleção anterior para formar uma instrução composta.
Não há chaves aqui porque uma única instrução pode ser lida sem chaves. Chaves são instruções em bloco.

Explicação detalhada das declarações
Como você pode ver à direita, aqueles com linhas horizontais apontando para cima são aqueles que até os iniciantes precisam dominar, enquanto aqueles com linhas horizontais abaixo são mais avançados;

1) Declaração-declaração

Insira a descrição da imagem aqui

  • declaração de variável local
int x;
x = 100;

// 和下面
int x = 100;

// 有什么区别?
// 二者不是一回事儿,前者叫做声明变量的时候没有初始化,而在后面进行了赋值,是两步操作;
// 后者叫做声明变量的时候追加了初始化器,是一步操作;
  • Declaração constante Constante
    : Quantidade cujo valor não pode ser alterado após ser declarado e inicializado;
int x = 100; // 值是可以改变的
const int y = 100; // 值在上下文是不可以改变的 const = constant
// const 常量必须在初始化的时候跟上初始化器,如果删掉的话,是编译不过去的;
2) Declaração de expressão

Insira a descrição da imagem aqui
Expressões que podem formar declarações;

Console.WriteLine("Hello"); // 方法调用表达式
new Form(); // 对象创建表达式,也就是new操作符创建的表达式
x = 100; // 赋值语句
++x;
--x;
x++;
x--;
// await 表达式,异步编程使用

O valor avaliado por esta expressão (se houver) é descartado

3) Bloco de instrução de bloco

Insira a descrição da imagem aqui
Uma instrução em bloco é equivalente a um contêiner para instruções. Uma instrução em bloco é uma instrução que pode conter várias instruções. Ela pode ser entendida como as chaves depois de if. As chaves são instruções em bloco; se as chaves estiverem vazias, elas são instruções de bloco vazias
. , esse uso é relativamente raro;
Insira a descrição da imagem aqui
as chaves na imagem acima não são instruções de bloco; a camada mais externa é o corpo do namespace, a segunda camada é o corpo da classe e a terceira camada é o corpo do método Main;
Insira a descrição da imagem aqui
somente quando aparece no método como este As chaves no corpo são instruções de bloco. A figura mostra uma instrução de bloco vazia, não há necessidade de adicionar um ponto e vírgula após a instrução de bloco;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
        	int y = 200;
            {
    
    
                int x = 100;
                if (x > 80)
                    Console.WriteLine(x);
                hello: Console.WriteLine("Hello World"); // 标签语句

                goto hello;
            }
        }
    }
}

Podemos ver que a instrução de bloco contém muitas subinstruções, mas o compilador sempre trata esta instrução de bloco comouma afirmação;
No exemplo acima, na instrução do bloco, você pode ver o y declarado fora do bloco; mas fora da instrução do bloco, você não pode ver o x declarado dentro da instrução do bloco;

4) Declaração de seleção (julgamento, ramo) Declaração de seleção

Insira a descrição da imagem aqui
instrução if
Insira a descrição da imagem aqui
instrução switch
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Exemplo de instrução switch:

int score = 95;
switch(score/10) // Switch 后面的表达式类型必须和case后面的表达式的类型一致;
{
    
    
	case 10: // case 后面的表达式必须是个常量表达式,变量则会编译报错
		if(score == 100)
		{
    
    
			goto case 8;
		}
		else
		{
    
    
			goto default;
		}
	case 8:
	case 9:
		Console.WriteLine("A");
		break; // 必须加上 break
	case 6:
	case 7:
		Console.WriteLine("B");
		break;
	case 4:
	case 5:
		Console.WriteLine("C");
		break;
	case 0:
	case 1:
	case 2:
	case 3:
		Console.WriteLine("D");
		break;
	default: // 类似if语句中的else,不符合前面所有条件,执行default的selection
		Console.WriteLine("Error!");
		break;
}

tente a declaração --------------------
Insira a descrição da imagem aqui

  • A instrução try pode usar a cláusula catch para capturar exceções e depois classificá-las para processamento;
  • A instrução try também pode conter uma instrução finalmente, ou seja, não importa o que aconteça ou nada aconteça na instrução, as cláusulas da cláusula final devem ser executadas;
  • Para instruções try, pode haver várias instruções catch, mas apenas uma instrução finalmente.Quando várias cláusulas catch aparecem, apenas uma delas pode ser executada e várias cláusulas catch não podem ser executadas;
  • Existem dois tipos de cláusulas catch, uma é universal e a outra só pode capturar um certo tipo de exceção;
namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Calculator calculator = new Calculator();
            int r = 0;
            try 
            {
    
    
                r = calculator.Add("123", "200");
            }
            catch (OverflowException oe)
            {
    
    
                // Add 没有处理的异常,交由调用者处理
                Console.WriteLine(oe.Message);
            }
                
            Console.WriteLine(r);
        }
    }

    class Calculator
    {
    
    
        public int Add(string arg1, string arg2)
        {
    
    
            int a = 0; // 提前声明
            int b = 0;
            bool hasError = false;
            try
            {
    
    
                a = int.Parse(arg1);
                b = int.Parse(arg2);
            }
            catch (ArgumentNullException ane) // 精细捕捉错误
            {
    
    
                Console.WriteLine("Your argument(s) are null");
                Console.WriteLine(ane.Message); // 通过标识符捕获异常的详细信息
                hasError = true;
            }
            catch (FormatException fe)
            {
    
    
                Console.WriteLine("Your argument(s) ar not number");
                Console.WriteLine(fe.Message);
                hasError = true;
            }
            catch (OverflowException oe)
            {
    
    
                // Console.WriteLine("Out fo range!");
                // Console.WriteLine(oe.Message);
                // hasError = true;
                throw oe; // 直接抛出异常,不在 Add 方法里处理
                // 谁调用谁处理
                // throw 关键字的语法比较灵活,后面没有标识符也是可以抛出的
                // 在 catch 中没有标识符时,也是可以抛出的
            }
            finally
            {
    
    
                // 通常 finally 子句包含了两类内容
                // 释放系统资源的语句,无论try语句是否异常,资源都会释放
                // 写程序的执行记录 Log
                if (hasError)
                {
    
    
                    Console.WriteLine("Execution has error!");
                }
                else 
                {
    
    
                    Console.WriteLine("Done!");
                }
            }
            int result = checked(a + b);
            return result;
        }
    }
}

Quando se descobre que uma determinada instrução pode gerar uma exceção, uma instrução try deve ser usada para executar a lógica;
o bug de travamento do programa é o mais sério de todos os bugs;
como desenvolvedor, você precisa lidar com tantas exceções quanto possível , caso contrário a revisão de final de ano será muito difícil. Feio, sem garantia de salários;

5) declaração de iteração (declaração de loop) declaração de iteração
  • instrução while
  • declaração
  • declaração for
  • instrução foreach

instrução while:
quando uma determinada condição é atendida, o corpo do loop é executado repetidamente ou o corpo do loop pode não ser executado; a
instrução while executa uma instrução incorporada de acordo com diferentes condiçõesZero ou mais vezes

while(booleam-expression)
{
    
    
	embedded-statement
}

// 例子
int score = 0;
bool canContinue = true;
while (canContinue )
{
    
    
	Console.WriteLine("Please input first number");
	string str1 = Console.ReadLine();
	int x = int.Parse(str1);
	
	Console.WriteLine("Please input second number");
	string str2 = Console.ReadLine();
	int y = int.Parse(str2);
	
	int sum = x + y;
	if (sum == 100)
	{
    
    
		score++;
		Console.WriteLine("Correct! {0}+{1}={2}", x, y, sum);
	}
	else
	{
    
    
		Console.WriteLine("Error! {0}+{1}={2}", x, y, sum);
		canContinue = false; // 当canContinue为false的时候,while的循环体就不再执行了
	}
}
Console.WriteLine("Your score is {0}.", score);
Console.WriteLine("GAME OVER");

instrução do
A instrução do executa uma instrução incorporada de acordo com diferentes condiçõesuma ou mais vezes

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int score = 0;
            int sum = 0;
            do
            {
    
    
                Console.WriteLine("Please input first number");
                string str1 = Console.ReadLine();
                int x = int.Parse(str1);

                Console.WriteLine("Please input second number");
                string str2 = Console.ReadLine();
                int y = int.Parse(str2);

                sum = x + y;
                if (sum == 100)
                {
    
    
                    score++;
                    Console.WriteLine("Correct! {0}+{1}={2}", x, y, sum);
                }
                else
                {
    
    
                    Console.WriteLine("Error! {0}+{1}={2}", x, y, sum);
                }
            }
            while (sum==100);
            Console.WriteLine("Your score is {0}.", score);
            Console.WriteLine("GAME OVER");
        }
    }
}

Instrução for
A instrução for é especialmente projetada para loops de contagem, portanto a legibilidade das condições de contagem é melhor do que while e do;
Insira a descrição da imagem aqui

  • for-initializer inicializador para loop for;
  • condição for A condição sob a qual o loop for pode ser executado;
  • for-iterator for executará este iterador uma vez após executar o corpo do loop;

Quando a instrução for começa a ser executada, o inicializador é executado e executado apenas uma vez;
então a condição é executada para determinar se o corpo do loop for foi executado. Quando verdadeiro, o corpo do loop é executado;
Insira a descrição da imagem aqui
pode-se ver que o contador é + após cada execução do corpo do loop. 1;
Não escreva variáveis ​​de loop fora de for, a menos que seja necessário;
se o inicializador, a condição de execução e o iterador de for não forem escritos, ele será escrito desta forma for( ; ; ), o que é equivalente a while True, loop infinito;
tabuada de multiplicação 9 por 9 Demonstração:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            for (int a = 1; a <= 9; a++)
            {
    
    
                for (int b = 1; b <= a; b++)
                {
    
    
                    Console.Write("{0}x{1}={2}\t", b, a, a * b); // \t 是制表符
                }
                Console.WriteLine();
            }
        }
    }
}

Insira a descrição da imagem aqui

A instrução foreach
é frequentemente chamada de loop de conveniência de conjunto, que costuma percorrer o conjunto;
a instrução foreach é usada para enumerar os elementos de um conjunto e executar uma instrução incorporada relacionada uma vez para cada elemento do conjunto;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int[] intArray = new int[] {
    
     1, 2, 3, 4, 5, 6};
            Console.WriteLine(intArray.GetType().FullName);
            Console.WriteLine(intArray is Array);

            IEnumerator enumerator = intArray.GetEnumerator();
            while (enumerator.MoveNext())
            {
    
    
                Console.WriteLine(enumerator.Current);
            }

            enumerator.Reset(); // 重置枚举器,否则下面的while不执行,因为上面执行完之后已经指向数组的末尾,需要重新指向集合的头
            while (enumerator.MoveNext())
            {
    
    
                Console.WriteLine(enumerator.Current);
            }
        }
    }
}

Insira a descrição da imagem aqui
Os exemplos acima descrevem os princípios subjacentes de travessia de coleção e iteradores;
foreach é uma abreviação para travessia de coleção;
Insira a descrição da imagem aqui
tipo de variável local:
identificador de tipo de dados local: variável de iteração, que é equivalente a um iterador que pega os elementos da coleção desde o início to end Referindo-se a todos eles,
a expressão é um conjunto, e o resultado final desta expressão é um conjunto;
se você obtiver o iterador e o conjunto, poderá acessar os elementos do conjunto um por um. Cada vez que um elemento for acessado , o corpo do loop é executado;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int[] intArray = new int[] {
    
     1, 2, 3, 4, 5, 6};
            Console.WriteLine(intArray.GetType().FullName);
            Console.WriteLine(intArray is Array);

            foreach (var current in intArray) // 这里鼓励大家保留 var 定义
            {
    
    
                Console.WriteLine(current);
            }
        }
    }
}

Insira a descrição da imagem aqui
A melhor situação de aplicação do foreach é percorrer a coleção! ! !
A melhor situação de aplicação do foreach é percorrer a coleção! ! !

6) Instrução de salto Instrução Junp

continue e break estão intimamente integrados com instruções de loop.
A instrução continue
abandona o loop atual e inicia um novo loop; os exemplos são os seguintes:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int score = 0;
            int sum = 0;
            do
            {
    
    
                Console.WriteLine("Please input first number");
                string str1 = Console.ReadLine();
                int x = 0;
                try
                {
    
     
                    x = int.Parse(str1);
                }
                catch 
                {
    
    
                    Console.WriteLine("First Number Has Problem! Restart");
                    continue; // 放弃本次循环,开启下一次循环
                }
                 

                Console.WriteLine("Please input second number");
                string str2 = Console.ReadLine();
                int y = 0;
                try 
                {
    
    
                    y = int.Parse(str2);
                }
                catch
                {
    
    
                    Console.WriteLine("Second Number Has Problem! Restart");
                    continue; // 放弃本次循环,开启下一次循环
                }

                sum = x + y;
                if (sum == 100)
                {
    
    
                    score++;
                    Console.WriteLine("Correct! {0}+{1}={2}", x, y, sum);
                }
                else
                {
    
    
                    Console.WriteLine("Error! {0}+{1}={2}", x, y, sum);
                }
            }
            while (sum==100);
            Console.WriteLine("Your score is {0}.", score);
            Console.WriteLine("GAME OVER");
        }
    }
}

Insira a descrição da imagem aqui
Pode-se observar que quando um erro no conteúdo de entrada é detectado, um ciclo é reiniciado.

A instrução break
encerra o loop imediatamente e não faz loop novamente;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            int score = 0;
            int sum = 0;
            do
            {
    
    
                Console.WriteLine("Please input first number");
                string str1 = Console.ReadLine();

                if (str1.ToLower() == "end")
                {
    
    
                    break; // 结束当前循环,不再开启新的循环
                }

                int x = 0;
                try
                {
    
     
                    x = int.Parse(str1);
                }
                catch 
                {
    
    
                    Console.WriteLine("First Number Has Problem! Restart");
                    continue; // 放弃本次循环,开启下一次循环
                }
                 

                Console.WriteLine("Please input second number");
                string str2 = Console.ReadLine();

                if (str2.ToLower() == "end")
                {
    
    
                    break; // 结束当前循环,不再开启新的循环
                }

                int y = 0;
                try 
                {
    
    
                    y = int.Parse(str2);
                }
                catch
                {
    
    
                    Console.WriteLine("Second Number Has Problem! Restart");
                    continue; // 放弃本次循环,开启下一次循环
                }

                sum = x + y;
                if (sum == 100)
                {
    
    
                    score++;
                    Console.WriteLine("Correct! {0}+{1}={2}", x, y, sum);
                }
                else
                {
    
    
                    Console.WriteLine("Error! {0}+{1}={2}", x, y, sum);
                }
            }
            while (sum==100);
            Console.WriteLine("Your score is {0}.", score);
            Console.WriteLine("GAME OVER");
        }
    }
}

Insira a descrição da imagem aqui

Depois de entrar no break, você pode ver que o programa é encerrado;

Deve-se notar que continue e break funcionam apenas em loops que contêm diretamente esta instrução, não em loops que contêm indiretamente esta instrução;

O princípio da declaração de retorno
é retornar o mais cedo possível. A seguir está um exemplo:
a imagem abaixo não é para retornar o mais cedo possível;
Insira a descrição da imagem aqui
a imagem abaixo é retornar o mais cedo possível: retornar
Insira a descrição da imagem aqui
o mais cedo possível. A vantagem O que é escrito desta forma é que permite que as pessoas que leem o código identifiquem rapidamente em que circunstâncias os parâmetros estão com problemas e evitem escrever todo o método muito pesado, para que a estrutura de todo o método fique clara;

Se o valor de retorno do método não for nulo e uma instrução de seleção for usada no corpo do método, deve-se garantir que o método possa retornar em cada ramificação de seleção.
A seguir está um exemplo:
Insira a descrição da imagem aqui
Se não for garantido que este método retorne em todas as ramificações, o programa dará errado;


Seção 8 Campos, propriedades, indexadores, constantes

Os quatro membros no título são todos usados ​​para expressar dados;
a essência de um programa é dados + algoritmo, e esses quatro são usados ​​para expressar dados, então falaremos sobre eles juntos; O
tipo C# tem os seguintes membros: O os
Insira a descrição da imagem aqui
da imagem acima Tipo refere-se a um subtipo aninhado em um tipo;

Parte 1 campocampo

O que são campos:

  • Um campo é uma variável que representa uma variável associada a um objeto ou tipo (classe e estrutura).É usado para armazenar dados.Múltiplos campos podem ser combinados para expressar o status atual de um objeto ou tipo;
  • Os campos são membros de um tipo, anteriormente conhecido comoVariáveis ​​de membro
  • Os campos associados a objetos também são chamados de campos de instância, que ajudam instâncias ou objetos a salvar dados.Ser afiliado a uma instância ou objeto ajuda os objetos a salvar seu estado atual;
  • Os campos associados aos tipos são chamados de “campos estáticos”, que são modificados por estáticos e pertencem a um determinado tipo de dados;

Insira a descrição da imagem aqui
A imagem acima mostra que o status do tipo de dados aluno é: não há muitos alunos, apenas dois. Este é o status atual do tipo expresso por meio de campos estáticos. O exemplo a seguir demonstra as funções de campos de instância e campos estáticos;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            List<Student> studentsList = new List<Student>();
            for (int i = 0; i < 100; i++)
            {
    
     
                Student student = new Student();
                student.Age = 24 + i;
                student.Score = i;
                studentsList.Add(student);
            }

            int totalAge = 0;
            int totalScore = 0;
            foreach (var student in studentsList) 
            {
    
     
                totalAge += student.Age;
                totalScore += student.Score;
            }

            Student.AverageAge = totalAge / Student.Amount;
            Student.AverageScore = totalScore / Student.Amount;

            Student.ReportAmount();
            Student.ReportAverageAge();
            Student.ReportAverageScore();

        }
    }

    class Student
    {
    
    
        public int Age;
        public int Score;

        public static int AverageAge;
        public static int AverageScore;
        public static int Amount;

        public Student() 
        {
    
    
            Student.Amount++;
        }

        public static void ReportAmount()
        {
    
    
            Console.WriteLine(Student.Amount);
        }

        public static void ReportAverageAge()
        {
    
    
            Console.WriteLine(Student.AverageAge);
        }

        public static void ReportAverageScore() 
        {
    
    
            Console.WriteLine(Student.AverageScore);
        }
    }
}

Declaração de campos: Em primeiro lugar, o nome do campo deve ser um substantivo;
o campo é um membro do tipo. Ao declarar um campo para uma classe, ele deve estar no corpo da classe. Se estiver escrito na função body, será uma variável local;

O método de declaração de campo mais comumente usado;

public int  Age;
访问级别,数据类型,变量名

public static int Amount;
访问级别,static,数据类型,变量名;

O comportamento de atribuir um valor no momento da declaração é o mesmo de inicializá-lo em seu construtor;

Tempo de inicialização:

  • Para campos de instância, quando a instância é criada, ela pode ser executada toda vez que uma instância é criada;
  • Para campos estáticos, quando o tipo de dados é carregado no ambiente de execução, ele só será executado quando o tipo de dados for carregado pela primeira vez, ou seja, o construtor estático será executado apenas uma vez;

Sem inicialização explícita, os campos obtêm o valor padrão de seu tipo e todos os campos "nunca são inicializados";

readonly Um campo somente leitura não pode receber um valor. Ele só pode ser inicializado para o campo e não pode receber um valor. Sua função é fornecer à instância um valor que ela não deseja alterar depois de inicializada;

Parte 2 PropriedadePropriedade

  • Um atributo é um tipo deAcessar características de um objeto ou tipoum membro de,Características refletem status

Entenda a frase acima através do seguinte exemplo:

有一块豆腐,这个豆腐有一个属性或者是特征温度,这个值非常高,反映了豆腐非常烫的状态;
如果这个属性特别低,说明豆腐是冻起来的状态;
  • As propriedades são uma extensão natural dos campos:
    • Do ponto de vista da nomenclatura, o campo está mais inclinado ao layout das instâncias na memória, enquanto a propriedade está mais inclinada a refletir as características dos objetos do mundo real;
    • Externamente, os dados são expostos e podem ser armazenados em campos e calculados dinamicamente;
    • Internamente, proteja os campos de serem "poluídos" por valores ilegais. Se você usar apenas campos, eles podem ser facilmente contaminados;
  • As propriedades evoluem a partir de pares de métodos Get/Set
namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student1 = new Student();
            student1.SetAge(20);

            Student student2 = new Student();
            student2.SetAge(20);

            Student student3 = new Student();
            student3.SetAge(20);

            int avgAge = (student1.GetAge() + student2.GetAge() + student3.GetAge()) / 3;
            Console.WriteLine(avgAge);
        }
    }

    class Student
    {
    
    
        private int age;
        public int GetAge()
        {
    
    
            return this.age;
        }

        public void SetAge(int value)
        {
    
    
            if (value >= 0 && value <= 120)
            {
    
    
                this.age = value;
            }
            else 
            {
    
    
                throw new Exception("Age value has error");
            }
        }
    }
}

Semelhante aos métodos Get e Set em Java, você pode proteger os campos de serem poluídos por valores ilegais no método Set.
A seguir é mostrado como usar métodos de atributos e wrappers para proteger os campos de serem poluídos por valores ilegais;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student1 = new Student();
            student1.Age = 20;

            Student student2 = new Student();
            student2.Age = 20;

            Student student3 = new Student();
            student3.Age = 20;

            int avgAge = (student1.Age + student2.Age + student3.Age) / 3;
            Console.WriteLine(avgAge);
        }
    }

    class Student
    {
    
    
        private int age; // 私有的字段

        public int Age // 公有的属性,是上面那个字段的包装器
        {
    
    
            // 现在就有了 Age 这个属性,这个就是 Age 属性的包装器
            get 
            {
    
    
                return this.age;
            }

            set 
            {
    
    
                // value 是默认的,不能变,且在特定环境下是上下文关键字;
                // 当在写 Setter 访问器,微软将其设定为关键字,代表传进来的,用户设定的值,出了Setter之后就不再是关键字了;
                if (value >= 0 && value <= 120)
                {
    
    
                    this.age = value;
                }
                else
                {
    
    
                    throw new Exception("Age value has error");
                }
            }
        }
    }
}

O exemplo acima mostra como um campo evolui para uma propriedade passo a passo através do método Get Set;

  • Os atributos são, na verdade, "açúcar sintático";

Parte 3 Indexador Indexador

Um indexador é um membro que permite que objetos sejam indexados da mesma forma que arrays (ou seja, usando subscritos); de modo geral, todos os
tipos de indexadores são tipos de coleção;
usar tipos que não são de coleção para explicá-los pode destacar a especialidade do indexador:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student();
            var mathScore = student["Math"];
            Console.WriteLine(mathScore); // 还没有数学成绩,打印不出任何东西

            student["Math"] = 90;
            mathScore = student["Math"];
            Console.WriteLine(mathScore); // 赋值之后,可以看到成绩
        }
    }

    class Student
    {
    
    
        private Dictionary<string, int> scoreDictionary = new Dictionary<string, int>();

        public int? this[string subject] // int? 是可空类型的int类型
        {
    
    
            get {
    
    
                /* return the specified index here */
                if (this.scoreDictionary.ContainsKey(subject)) // 先索引有没有这个key
                {
    
    
                    return this.scoreDictionary[subject]; // 有
                }
                else
                {
    
     
                    return null; // 没有
                }
            }
            set {
    
    
                if (value.HasValue == false) // 如果 value 是一个空值,使用 throw 扔出一个异常
                {
    
    
                    throw new Exception("Score cannot be null");
                }
                /* set the specified index to value here */
                if (this.scoreDictionary.ContainsKey(subject))
                {
    
    
                    // 如果存在,更新这个值
                    this.scoreDictionary[subject] = value.Value; // Value 代表传进来的值,对于可空类型,value.Value 才是真正的值
                }
                else
                {
    
    
                    // 如果不存在,添加这个值
                    this.scoreDictionary.Add(subject, value.Value);
                }
            }
        }
    }
}

Insira a descrição da imagem aqui
Como no exemplo acima, é muito raro usar indexadores do tipo que não sejam de coleção;

Parte 4 const constante

Constante representa um valor constante. Quando o compilador compila o código, ele substitui o identificador da constante por um valor para melhorar a eficiência; a constante
pertence a um tipo e não a um objeto, ou seja, não há constante de instância
(o papel de uma constante de instância é reproduzida por um campo de instância somente leitura))
É necessário prestar atenção para distinguir constantes de membro e constantes locais:
vários cenários de aplicativos somente leitura:

  • Para melhorar a legibilidade e eficiência de execução do programa – constantes;
  • Para evitar que o valor do objeto seja modificado – campos somente leitura;
  • Exponha dados que não podem ser modificados para o mundo externo - atributos somente leitura (estáticos ou não estáticos). As funções têm alguma sobreposição com constantes. Qual delas é mais eficiente, usando constantes ou atributos estáticos somente leitura: O uso de constantes tem desempenho superior;
  • Quando o tipo do valor que se espera ser uma constante não pode ser aceito pela declaração da constante (classe/estrutura customizada) – campo do sistema estático;

Seção 9 Passagem por valor, saída, referência, array, nomeado, parâmetros opcionais, método de extensão

Parâmetro de valor da parte 1

Também chamados de parâmetros de passagem por valor, parâmetros sem quaisquer modificadores quando declarados são parâmetros de valor. Eles são essencialmente variáveis ​​locais cujo escopo está no método atual. O valor inicial é o valor do parâmetro real atribuído quando o método é chamado.
O parâmetro value é equivalente a uma variável local recém-declarada ou a uma cópia do parâmetro real passado, portanto, atribuí-lo no corpo do método não afetará o valor do parâmetro real; o exemplo a seguir é um uso de parâmetro de tipo de valor
Insira a descrição da imagem aqui
:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = new Student();
            int y = 100;
            student.AddOne(y);
            Console.WriteLine(y);
        }
    }

    class Student
    {
    
    
        public void AddOne(int x) // 这个 x 是值参数,这个就是值类型的传值参数
        {
    
    
            x = x + 1;
            Console.WriteLine(x);
        }
    }
}

Insira a descrição da imagem aqui
O exemplo a seguir é o uso de parâmetros de valor passado do tipo de referência:

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student stu = new Student() {
    
     Name = "Tim"};
            SomeMethod(stu);
            Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name); // 可以看到这里打印的 HashCode 与 SomeMethod 中的 HashCode 不一样
            // GetHashCode() 可以认为是获取实例对象的某个编号,是唯一的,每个实例的编号都不一样;
            // 如果方法没有使用副本而是使用本体,那么程序打印出来的 HashCode 应该是一样的,不一样就是产生了新的实例
        }

        static void SomeMethod(Student stu)
        {
    
    
            stu = new Student() {
    
     Name = "Tim" };
            Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);
        }
    }

    class Student
    {
    
    
        public string Name {
    
     get; set; }
    }
}

Insira a descrição da imagem aqui

Parte 2 Parâmetros de referência

Os parâmetros formais declarados usando o modificador ref no momento da declaração são diferentes dos parâmetros de valor. Os parâmetros de referência não criam um novo local de armazenamento. Pelo contrário, o local de armazenamento do parâmetro de referência é exatamente a variável fornecida como um parâmetro real no chamada de método. O local de armazenamento representado;
ou seja, o parâmetro de referência aponta para o endereço de memória do parâmetro real passado; (eu pessoalmente acho que é semelhante a um ponteiro;);
Deve-se notar que ao chamar o método de referência parâmetro, o parâmetro real deve receber um valor e usar A palavra-chave ref deve ser adicionada;
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui


Insira a descrição da imagem aqui
Insira a descrição da imagem aqui


Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
A função de passagem de valor cria uma cópia dos parâmetros reais na memória, ou seja, os endereços reais de student e outerStu são diferentes, mas o endereço da mesma instância na memória heap é armazenado; e a primeira imagem usa aquela que refere-se ao parâmetro ref, ambos são o mesmo endereço;

Parte 3 Parâmetros de saída

Parâmetros formais declarados com o modificador out são parâmetros de saída; métodos com parâmetros de saída podem obter saída adicional além do valor de retorno;
parâmetros de saída não precisam ser atribuídos antes de passar para o método
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Método autoimplementado com parâmetros de saída


Insira a descrição da imagem aqui

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Student student = null;
            bool b = StudentFactory.Create("Tim", 34, out student);
            if (b == true)
            {
    
    
                Console.WriteLine("Student {0}, Age is {1}", student.Name, student.Age);
            }
        }
    }

    class Student
    {
    
    
        public int Age {
    
     get; set; }
        public string Name {
    
     get; set; }
    }

    class StudentFactory
    {
    
    
        public static bool Create(string stuName, int stuAge, out Student result)
        {
    
    
            result = null;
            if (string.IsNullOrEmpty(stuName))
            {
    
    
                return false;
            }
            if (stuAge < 20 || stuAge > 80)
            {
    
    
                return false;
            }

            result = new Student() {
    
     Name=stuName, Age=stuAge};
            return true;
        }
    }
}

Insira a descrição da imagem aqui
Este exemplo é usado para explicar os parâmetros de saída dos tipos de referência;

Parte 4 Parâmetros de array

Os parâmetros do array devem ser modificados com o modificador params quando declarados;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
        	int[] myArray = new int[] {
    
    1, 2, 3}; // 不需要再这样声明完数组 myArray;
            int result = CalculateSum(1, 2, 3); 
            // 意味着并不需要提前声明一个数组,可以以 params 的形式输入在这,编译器会自动声明数组
            Console.WriteLine(result);
        }

        static int CalculateSum(params int[] intArray)
        {
    
     
            int sum = 0;
            foreach (var item in intArray) 
            {
    
    
                sum += item;
            }
            return sum;
        }
    }
}

Em uma lista de parâmetros, só pode haver um parâmetro params e só pode ser o último;

Parte 5 Parâmetros nomeados

Isso significa que ao chamar um método, os parâmetros passados ​​possuem nomes.

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            PrintInfo(name: "TIM", age: 34); // 这个就是具名调用
        }

        static void PrintInfo(string name, int age)
        {
    
    
            Console.WriteLine("Hello {0}, you are {1}", name, age);
        }
    }
}

Existem duas vantagens:

  • Melhorar a legibilidade do código;
  • Com a adição de nomes, a ordem dos parâmetros não fica mais restrita pela ordem de posição da lista de parâmetros;

Parte 6 parâmetros opcionais

Ao chamar um método, este parâmetro é opcional e possui um valor padrão;
Insira a descrição da imagem aqui

Parte 7 Método de extensão (este parâmetro)

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            double x = 3.14159;
            double y = x.Round(4); // x 是 Round 方法的第一个参数,所以只需要输入第二个参数
            Console.WriteLine(y);
        }
    }

    static class DoubleExtension
    {
    
    
        public static double Round(this double input, int digits)
        {
    
     
            double result = Math.Round(input, digits);
            return result;
        }
    }
}

Quando não podemos modificar o código-fonte de um tipo, podemos usar métodos de extensão para adicionar métodos ao tipo de dados de destino;
Insira a descrição da imagem aqui
sem usar LINQ

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using ClassTest;
using System.Dynamic;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            List<int> myList = new List<int>() {
    
     11, 12, 13, 14, 15};
            bool result = AllGreaterThanTen(myList);
            Console.WriteLine(result);
        }

        static bool AllGreaterThanTen(List<int> intList)
        {
    
     
            foreach (var item in intList) 
            {
    
     
                if (item <= 10)
                {
    
    
                    return false;    
                } 
            }
            return true;
        }
    }
}

Usando LINQ:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using ClassTest;
using System.Dynamic;
using System.Linq;

namespace ConsoleHelloWorld
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            // 判断 myList 中是不是所有数都大于 10
            List<int> myList = new List<int>() {
    
     11, 12, 13, 14, 15};
            // All() 是扩展方法
            bool result = myList.All(i => i > 10); // All 方法可以接受委托类型的参数
            Console.WriteLine(result);
        }
    }
}

Resumo da Parte 8

Insira a descrição da imagem aqui

Acho que você gosta

Origin blog.csdn.net/qq_17790209/article/details/132416939
Recomendado
Clasificación