-
As coisas ficam mais legais a partir da aula 9
-
Veja os códigos das aulas na pasta CFB
Otávio Dioscânio /2020
[TOC]
OS - Windows - Microsoff.Net - Framework64 - csc.exe
- csc.exe é o compilador C#
- pesquisar csc no prompt: mostra se está no path do sistema (provavelmente não vai estar). Logo, deve-se baixar o .Net SDK, o .Net Framework DevPack, o .Net Runtime
- Programação orientada a objetos: todo programa me C# é uma classe
- dir: revela o que está na pasta
- apenas digitar o nome do arquivo para executá-lo
- Compilar no prompt: csc Aula01.cs
- Abrir uma pasta: cd Aula01
- cls limpa o prompt
using System;
class Exercicio1 {
static void Main() {
Console.WriteLine("Olá mundo!");
}
}
Padrão dotnet: interface similar à JVM, para rodar em vários dispositivos Namespace organiza as classes
-
int num; //deixa ele como 0
-
Declaração e atribuição
-
primitivas: int, char, float, byte
float valor = 3.2f
byte n1 = 10; // entre 0 e 255, não tem sinal. 8 bits
-
String não é primitiva
var numero = 10; //quando não quiser especificar o tipo. É atribuído na compilação
- Variáveis dentro de métodos podem ser declaradas como var em C# que o seu tipo é inferido automaticamente. Para o compilador acertar qual o tipo da variável ela deve ser inicializada no mesmo instante que é declarada e não pode ser atribuído o valor null.
- Atenção: usar var não deixa de definir bem o tipo. Este não pode ser alterada à medida que o código é executado!
int num1=0, num2=0;
- Onde ela é visível, pode ser utilizada
bool res = 10 < 5; // False
num = num + 1;
num += 1; num *= 2;
num++; // só funciona para somar 1``
bool res = (5 > 3) | (10 < 5);
- Lembrando que Console.WriteLine(); quebra linha.
- Em vez de concatenar, utilizar índices a partir do 0.
- \n quebra linha
- \t insere um tab
Console.WriteLine("Val.Compra...:{0,15:c}", valorCompra);
- c: valor monetário, p: porcentagem.
- Uma vez atribuído um valor, ele não pode modificar (senão dá erro).
- Tipo uma proteção para a variável.
- Palavra reservada: const.
- O restante é igual às variáveis.
const string canal = "CFB Cursos";
const double pi = 3.1415;
- Console.Read() ou Console.ReadLine()
- ReadLine quebra linha (ou adiciona uma?) depois do enter
- Cuidado: tudo que é lido vai no formato String Duas formas de converter:
v1 = int.Parse(Console.ReadLine());
v2 = Convert.ToInt32(Console.ReadLine());
Bitwise para esquerda <<: dobra o valor da variável Os cinco últimos bits vão para a esquerda, completando um 0 no final ex.: 001010 = 10 010100 = 20 Para a direita >> : divide por 2 Elimina o último bit e desloca tudo para a direita 011010 = 26 001101 = 13
int num = 10;
num = num >> 1; // desloca apenas 1 (divide apenas uma vez)
Console.WriteLine(num); // 5 (para a direita divide)
di-di (direita divide)
int num = 10;
num = num << 2;
Console.WriteLine(num); //40
cabo 11:49 23/09/2020
- Criar um tipo personalizado com valores predefinidos
enum DiasSemana {Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado}
DiasSemana ds = DiasSemana.Domingo; // DiasSemana é o tipo de ds
- Converter o valor 3 no tipo DiasSemana
DiasSemana ds = (DiasSemana)3; // uso de cast
Console.WriteLine(ds); // Quarta
int ds = (int) DiasSemana.Sexta;
Console.WriteLine(ds); // 5
-
Quando a conversão não é implícita/segura
-
Não serve quando precisa de int.Parse ou Convert.ToInt32
-
Conversões implícitas: int -> float, int -> long
int n1 = 10;`
float n2 = n1; // converte automaticamente
Console.WriteLine(n2);
float n2 = 10.5f;
int n1 = n2; // float -> int não tem conversão implícita, mas existe a explícita
float n2 = 10.5f;
int n2 = (int) n1; // typecast, explícita.
int vInt = 10;
short vShort = (short) vInt; // cuidado
decimal numeroGrande = 10;
double numeroPequeno = 25;
numeroPequeno = (double) numeroGrande;
Console.WriteLine(numeroGrande + " " + numeroPequeno);
short valorPequeno = 100;
long valorGrande = 25;
valorGrande = valorPequeno; // não precisa do cast pois long > short
Console.WriteLine(valorGrande);
Aula 12 - condicional if
Aula 13 - if, else if, else
- lembrar que pode mudar a ordem e que não precisa de duas expressões no condicional
Aula 14 - if aninhados: if dentro de outro
- Compara uma variável com seus cases
int tempo = 0;
char escolha;
escolha = char.Parse(Console.ReadLine());
switch (escolha) {
case 'a':
case 'A': // testa os dois
tempo = 50;
break; // faz parte da estrutura padrão do case
case 'c':
tempo = 480;
break;
case 'o':
tempo = 660;
break;
default:
tempo =-1;
break;
}
switch (variavelIndicada) {case}
- Dúvidas: o default é obrigatório?
- Antigo, de uma época em que não existiam estruturas de repetição (programação em fluxo, e não estruturada que nem hoje).
- Pode ser útil e tornar o código legível (ex.: loops profundamente aninhados)
- Gera um desvio no programa para um ponto determinado
- Cuidado, ele pode criar loops invisíveis
inicio: // label
...
goto inicio;
while: if x >= 10 goto end
print x
x++
goto while
end:
tryAgain:
try {
...
} catch (...) {
goto tryAgain;
}
return !(cond1 || cond2 || cond3);
- Coleção de variáveis do mesmo tipo
- tipo, colchetes nome recebe new tipo [tamanho];
- Mais fácil para criar, atribuir e ler variáveis
int[] meuArray = new int [5]; // 0-4
meuArray[0] = 111;
meuArray[1] = 200; meuArray[3] = 400; meuArray[4] = -20;
Console.WriteLine(meuArray[0]); // 111
string[] veiculos = new string[3];
- Já atribuindo na declaração
int[] numeros = new int[3] {55, 77, 99};
Console.WriteLine(numeros[2]); // 99
- Também dá:
int[] num = {55, 77, 99, 66, 88}; // não fica com tamanho limitado.
- dúvida: não colocar o new tipo[tamanho] deixa o vetor dinâmico? Posso adicionar elementos após a criação?
-
Utiliza dois índices para localizar os elementos
-
É como se fosse uma tabela, índices de linha e coluna
-
No operador (colchetes) coloca-se uma vírgula
-
Os índices podem ter tamanhos diferentes
int [,] n = new int [3,5]; // linha, coluna
/*
10 20 30 40 50
60 70 80 90 15
25 35 45 55 65
*/
n[0,0] = 10; n[0,1] = 20; n[0,2] = 30; n[0,3] = 40; n[0,4] = 50;
n[1,0] = 60; n[1,1] = 70; n[1,2] = 80; // ...
n[2,0] = 25; n[2,1] = 35; // ...
int [,] num = new int [2,2] {{10,20}, {30,40}}; // primira linha, segunda linha
for (int num = 0; num < 10; num + 1) {}
// declarar internamente: num só serve no escopo do for.
// enquanto a condição for verdadeira, ele vai executar
// obs.: ele começa e imprimir no 0 e vai até o 9, passando por 10 números
int[] num = new int[10];
for (int i = 0; i < num.Length; i++) {
num[i] = i;
}
num.Length
- tamanho do array (não é o último índice)- for é geralmente usado quando se tem certeza das vezes que o comando será repetido
- Inicialização e atribuição do contador antes do while
- Operação de incremento dentro
int [] num = new int[10];
int i = 10;
while (i > 0) {
Console.WriteLine(i);
i--;
} // 10-1
- Lembre-se que a última posição de um array é array.Length - 1
- Garante-se que, pelo menos uma vez, os comandos serão executados
do {
Console.WriteLine(i);
i++
} while (i < 5);
string senha = "123";
string senhauser;
int tentativas = 0;
do {
Console.Clear();
Console.WriteLine("Digite a senha");
senhauser = Console.ReadLine();
tentativas++
} while (senhauser != senha);
Console.WriteLine("Senha correta. Tentativas: {0}", tentativas);
- obs.: Console.ReadKey();
- Próprio para ler elementos de uma coleção
- Cria uma variável que vai receber cada elemento da coleção (logo, precisa ser do mesmo tipo)
int [] num = new int[5]{11, 22, 33, 44, 55};
foreach(int n in num) {
Console.WriteLine(n); // coloca os valores no n. Não tem contador
}
- Não é possível atribuir valor a n dentro do foreach (??)
- Legenda: vetor = um array qualquer
Random aleatorio = new Randow(); // classe Random, objeto aleatorio
int valor = aleatorio.Next(50);
int valor1 = aleatorio.Next(-5, 250);
int tamanho = vetor.Length;
foreach (int elemento in vetor) { }
Array.BinarySearch (vetorPesquisa, valorProcurado);
- retorna a posição. O array precisa estar ordenado (?). Caso não exista, retorna negativo.
Array.Copy(vetorOrigem, vetorDestino, quantidadeElementos);
- quantidadeElementos conta a partir do 0?
vetorOrigem.CopyTo(vetorDestino, posicaoInicial);
vetor1.CopyTo(vetor3, 0);
vetor.GetLowerBound(dimensão);
vetor.GetUpperBound(dimensão);
- retorna o menor/maior índice do vetor ou matriz (?)
vetor.GetValue(indice);
- retorna object. indice é long. também serve para matriz
Array.IndexOf(vetor, valor);
- posição da primeira ocorrência. -1 se não existir. somente para vetor unidimensional.
Array.Reverse(vetor);
vetor.SetValue(object valor, long indice);
Array.Sort(vetor);
- Métodos são conjuntos de instruções, um bloco que pode ser invocado a qualquer momento;
- Void: não retorna
- É static pois o método principal também é
- Os argumentos não precisam ser do mesmo tipo
static void Main() {
int num = 10;
dobrar(ref num); // ref na hora de passar
Console.WriteLine(num); // 20
}
static void dobrar(ref int valor) { // ref no método
valor *= 2;
}
- A variável passada por parâmetro com ref entra no método, executa o código, e sai como se fosse global.
- Cuidado: passagem por referência afeta variáveis, mesmo não havendo o
return
valor
aponta para o endereço de memória denum
- Tem que usar o ref também na hora de chamar o procedimento e passar o parâmetro
- Possibilidade de o método ter mais de um valor de saída
static void Main() {
int divid, divis, quoci, rest;
dividendo = 10;
divisor = 5;
quoci = divide (divid, divis, out rest); // tem que usar o out aqui também
Console.WriteLine(...)
}
static int divide (int dividendo, int divisor, out int resto) {
int quociente = dividendo / divisor;
return quociente;
}
// return quociente, resto; -> não existe!!
out rest
out int resto
- pelo visto você cria uma variável vazia que vai entrar no método só para receber um valor e voltar.
- Não precisa especificar o número de argumentos, pode ser 0 ou n.
- Deve-se colocar uma forma de controle (ex.: if, else if) dentro do método
static void Main() {
soma (10, 7, 8, 1, 4, 2);
soma ();
soma (1, 2);
}
// ---- jeito limitado (aceita até 2 parâmetros):
static void soma (int n1, int n2) {
int res = n1 + n2;
Console.WriteLine("A soma é " + res);
}
// --- com params - permite zero ou mais:
static void somaFlexivel (params int[] nomeArray) {
int res = 0;
if (nomeArray.Length < 1) {
Console.WriteLine("Não existem valores para somar")
} else if (nomeArray.Length < 2) {
Console.WriteLine("Valores insuficientes");
} else {
for (int i = 0; i < nomeArray.Length; i ++) {
res += nomeArray[i];
}
}
}
-
Classe: tipo de dado composto por membros (variáveis e métodos/funções da classe).
-
Onde vão ser instanciados os objetos. É a base, define o comportamento deles.
-
Objetos são independentes entre si, são instanciados em lugares diferentes da memória
-
[ModificadorClasse] class NomeDaClasse {
// variáveis / propriedades
[EspecificadorAcesso] tipo NomePropriedade;
// métodos
[EspecificadorAcesso] retorno NomeMetodo([arg1, ...]) {
// corpo do método
}
}
-
-
public: pública, sem restrição de visualização ou acesso em qualquer parte do programa. Não é o padrão se for omitido (e sim internal).
-
abstract: classe-base para outras classes, não pode gerar objetos.
-
sealed: selada, dela não pode haver herdeiros
-
static: não pode ser instanciada, mas é possível acessar seus membros, que também devem ser estáticos.
- tudo que vai ser usado no construtor (Main) static deve ser static também.
-
-
EspecificadorAcesso:
- public: sem restrição de acesso - qualquer membro, inclusive fora da classe, sem um método para isso. É o padrão.
- private: só podem ser acessados pela própria classe. É o padrão.
- protected: acessado na própria classe e nas classes derivadas (herança)
- abstract: só há a implementação do cabeçalho do método, não a definição dele (que fica no bloco de código).
- Obriga a implementação do método na classe que está herdando da classe pai
- sealed: o método não pode ser redefinido
- virtual: o método pode ser redefinido em uma classe derivada
- static: o método pode ser chamado mesmo sem instanciar um objeto
- pode usar o membro static sem precisar do New para instanciar
-
Futuramente: métodos construtores, destrutores
-
Boa prática: nome da classe com letra maiúscula.
-
Obs.: ainda não sei os defaults de class, main, variáveis
-
As classes e estruturas por padrão são
internal
, já os membros de classe/estrutura são privados por padrão.-
Quando queremos trabalhar com bibliotecas externas ao projeto, nossas classes precisam ser declaradas com a visibilidade public
-
class Cliente { // internal class Cliente }
-
-
Uma vez que um objeto é criado, ele ganha uma posição estática na memória. Possui seus próprios atributos independentemente.
-
É possível que mais de uma variável aponte para o mesmo objeto e, caso haja modificação deste, será visível para todas as variáveis ao mesmo tempo
-
new
: aloca a memória para um objeto e retornar o endereço dela
public class Jogador {
public int energia = 100;
public bool vivo = true;
}
public class Aula28 {
static void Main() {
Jogador j1 = new Jogador(); // criou o objeto j1 da classe Jogador
Jogador j2 = new Jogador(); // instanciamento sem parâmetros
Jogador j3 = new Jogador();
j1.energia = 50;
Console.WriteLine("Energia do jogador 1: {0}.", j1.energia);
Console.WriteLine("Energia do jogador 2: {0}.", j2.energia);
// 50, 100 (são independentes)
}
}
Conta mauricio = new Conta(); // mauricio aponta a um objeto
mauricio.Saldo = 2000;
Conta copia = mauricio; // copia passa a apontar para esse objeto (não cria outro)
copia.Saldo = 3000;
MessageBox.Show("Mauricio = " + mauricio.Saldo); // 3000
MessageBox.Show("Copia = " + copia.Saldo); // 3000
- Método construtor: atua no objeto quando instanciado, tem a função de inicializar as propriedades/variáveis.
- Toda classe tem um construtor, mesmo que não seja explícito
- construtor padrão dentro da classe - não recebe argumentos e não executa nenhuma ação (tem o corpo vazio)
- Basta que o método tenha o mesmo nome da classe
public
+NomeDaClasse(){ }
public class Jogador {
int energia; bool vivo;
public Jogador() { // método construtor
energia = 100;
vivo = true;
}
}
- É possível passar parâmetros para o Construtor da classe
public class Jogador {
int energia; bool vivo;
String nome;
public Jogador(String n) {
energia = 100; vivo = true;
nome = n;
}
}
- Aí precisa colocar o nome ao instanciar:
Jogador j1 = new Jogador("Zenifreudo"); // ou zigofreudo
- Método destrutor: chamado antes de o objeto ser destruído pelo garbage collector.
- Não precisa definir visibilidade. Apenas um ~ seguido do nome da Classe.
nome = n; // continação, ainda dentro de classe
}
~Jogador() {
Console.WriteLine("Jogador foi destruído");
}
- Permite mais um construtor para a classe.
- Vários construtores de mesmo nome, mas o conjunto de parâmetros é diferente.
- Obs.: sobrecarga de métodos é mesma coisa
public Jogador () { }
public Jogador (string n, int e) { }
// etc
Jogador j1 = new Jogador();
Jogador j3 = new Jogador ("Théo", 50);
// etc
- No C#, ao invés de fazer sobrecarga de construtores, pode ser bom utilizar parâmetros opcionais com valores padrão.
- Um construtor pode chamar outro:
this(parametro)
Conta (String titular) {
this.titular = titular;
}
Conta (int numero, String titular) {
this(titular); // chama o construtor de cima
this.numero = numero;
}
- Não se pode instanciar a partir de uma classe declarada como static.
- Logo, classes static não permitem o uso de construtores. O objeto static utiliza uma posição fixa na memória, não se usa
new
.
static public class Jogador {
static public int energia; // todos os membros são static também
static public bool vivo;
static public string nome;
static public void iniciar (string n) { // propriedades
energia = 100;
vivo = true;
nome = n;
}
//...
}
- Todos os membros (propriedades e métodos) são obrigatoriamente static também.
- Classe disponível em todo o programa sem precisar instanciar um objeto.
class Aula31 {
static void Main () {
Jogador.iniciar("Otávio"); // acessa-se pela própria classe
Jogador.info();
}
}
- A chamada é pela própria classe static, não há objetos (j1, j2, j3...)
- Alterar uma propriedade da classe: surte efeitos em todo o sistema, pois o local da memória que todos acessam é fixo e comum.
- Pode ter objetos.
- Uma classe não static pode ter um membro static, mas não é obrigatório.
- Neste caso, todos os objetos da classe vão apontar para a mesma propriedade, eles não terão uma própria.
- Não é possível modificar individualmente.
- Sem propriedade static:
class Inimigo {
public bool alerta; // não é static
public string nome;
public Inimigo(string n) {
alerta = false;
nome = n;
}
//...
}
class Aula31 {
static void Main () {
Inimigo i1 = new Inimigo("Doido");
Inimigo i2 = new Inimigo("Maluco");
i1.alerta = true; // funciona pois alerta não é static
//...
}
- Com
alerta
static:
class Inimigo {
static public bool alerta;
public string nome;
//...
static void Main () {
Inimigo i1 = new Inimigo("Doido");
Inimigo i2 = new Inimigo("Maluco");
Inimigo.alerta = true; // e não: i1.alerta = true;
i1.nome = "oi"; // pode pois nome não é estático
}
- Faz referência à propriedade da classe, e não do método. Ao objeto pai.
class Calculos {
public int v1; // esse daqui é representado pelo this
public int v2;
public Calculos (int v1, int v2) {
/*v1 = v1;
v2 = v2;*/
this.v1 = v1;
this.v2 = v2;
}
- Propriedades
private
são inacessíveis fora da classe, tanto para escrita quanto para leitura. - Proteção aos membros: não dá para mudar/acessar sem um método público que permita.
- define-se, inclusive, os valores aplicáveis à variável, se fosse
public
qualquer valor seria aceito. - filtro do valor a ser atribuído
- define-se, inclusive, os valores aplicáveis à variável, se fosse
-
É um recurso da POO em que uma classe derivada (filha, subclasse) herda membros, propriedades e classes de uma classe base (pai, base)
-
Evidentemente, a classe derivada pode ter seus membros próprios
-
Importante: só herda o que for
public
-
Uma classe derivada tem o nome da classe base depois de dois pontos
class Carro:Veiculo {
- Pode ter espaço entre os dois
- Caso queira modificar a regra de negócio de um método:
- Colocar
virtual
no método da classe pai, dizendo que ele pode ser sobrescrito pela filha - Reescrever o método na filha com
override
antes
- Colocar
- O construtor da classe filha pode passar parâmetros para o construtor da classe base e executá-lo.
class Veiculo { // classe base
public Veiculo (int rodas) { // construtor
- Construtor da classe derivada:
class Carro: Veiculo { // classe derivada
//...
public Carro(string nome, string cor):base(4) {
base()
é palavra reservada que, neste caso, se refere ao construtor da classe pai
- Imagine uma outra classe que herda Carro (que já herda Veículo)
class CarroCombate:Carro {
public int municao;
public CarroCombate():base("Carro de batalha", "verde") {
municao = 100;
ligar();
setRodas(6);
}
}
- Na hora de instanciar:
CarroCombate cc1 = new CarroCombate();
return (ligado ? "sim" : "não");
([expressão] ? [valor1] : ([expressão] ? [valor1] : ([expressão] ? [valor1] : [valor2])))
- Não pode ficar sem o
else
, nem colocarnull
no lugar dele.
-
Atributos privados só são visíveis para a classe que os declarou. Os filhos não enxergam.
-
Atributos/métodos marcados como
protected
são visíveis apenas para a própria classe e para as classes filhas. -
No exemplo anterior Veiculo não conseguiria acessar propriedades ou atributos private.
- Ao instanciar um objeto de
Derivada2
, todos os construtores serão executados. - A ordem de execução de construtores é sempre da base para a derivada.
- No código, base -> derivada1 -> derivada2
-
São métodos que têm o mesmo nome mas estão em classes diferentes, sendo que uma herda a outra
-
Executam uma ação diferente
-
Virtual: será sobrescrito em uma classe derivada
-
Override: vai sobrescrever em uma classe derivada
virtual public void info() { // quem é virtual pode ser sobrescrito. Está na classe pai
}
// ...
override public void info() { // sobrescreve. Está na classe filha
}
// ...
override public void info() { // classe mais específica, sobrescreve
}
deriv2.info();
- Não precisa codificar o método virtual, já que ele não será executado, deixe o espaço entre chaves vazio (não precisa de definições, só da assinatura)
- Percebi que usar as palavras
virtual
ouoverride
só evitar warnings, mas o código compila sem elas.
- É possível reutilizar o comportamento do método da classe pai, usando a palavra
base
public class ContaPoupanca : Conta
{
public override void Saca(double valor)
{
base.Saca(valor + 0.10);
}
}
Base Ref;
Ref = deriv2;
Ref.info(); // "Derivada2"
-
Ref
tem que ser com letra maiúscula, é palavra reservada. -
Elemento de referência que pode receber as classes derivadas dessa base
- Classe abstrata: classe de referência/base para outras classes que vão herdar dela.
- Não dá para instanciar objetos!
- Não pode ser
sealed
ouabstract
- Em métodos abstratos, não se implementa o comportamento, cria-se apenas o protótipo que vai servir como guia para as classes herdeiras. Não há conteúdo.
- Obriga que as classes derivadas implementem os métodos
- Métodos não abstratos: contêm a implementação, que é obrigatória.
- Esqueceu? [Veja aqui](#Tipos Classe)
abstract public void aumentarPeso(int peso); // é obrigatório que seja sobrescrito
override public void aumentarPeso(int peso){
this.peso += peso;
}
- Resumo: é um guia, obriga implementação, não tem código. Usar ponto e vírgula.
- Uma classe abstrata pode não ter um método abstrato, mas todo método abstrato precisa estar em uma classe abstrata
- Classe selada: não pode ser herdada.
sealed class Comida {
- Dá para instanciar objetos normalmente, só não pode usá-la como base.
- É possível ler, atribuir ou calcular pela propriedade Acessor
- Nunca devemos expor os atributos da classe utilizando o
public
.- Inclusive usar os Acessors facilita a manutenção do código, caso sejam alteradas as regras de negócio.
- Deixar o set privado é importante também, pois de nada vale deixar outras classes modificarem o atributo pela propriedade - o encapsulamento seria inútil.
- Não é obrigatório implementar um
get
(read) e umset
(write) juntos. Inclusive eles podem ser privados value
é o valor atribuído à propriedade.
public int Peso { // não possui parâmetros
get {
return peso;
}
private set { // não confundir Peso com peso!
if (value < 0)
peso = 0;
else if (value > 200)
peso = 200;
else
peso = value;
} // set não tem return
}
bicho.Peso = 140; // usa o acessor set
Console.WriteLine("Peso: " + bicho.Peso); // usa o get
- Auto-implemented properties - a partir do C# 3.0
- ao utilizarmos as auto-implemented properties, só podemos acessar o valor do atributo declarado através da propriedade (mesmo que seja de dentro da classe).
class Conta
{
public int Numero { get; set; }
}
- Membro de uma classe que permite que os objetos dela possam ser indexados como arrays.
- Aplicação (ex.): valores diferentes em situações diferentes
- Obs.:
this
é o que indexa - Dúvidas: 1) onde está a referência no cabeçalho do indexador de que é o peso a ser indexado e acessado pelos objetos? 2) só pode um indexador por classe? poderia ter bicho.peso[1] e bicho.altura[2]?
private int[] peso = new int[5]{80, 120, 160, 240, 300};
public int this[int i] { // indexador
get {
return peso[i];
}
set {
if (value < 0)
peso[i] = 0;
else if (value > 200)
peso[i] = 200;
else
peso[i] = value;
}
}
Console.WriteLine("Peso: " + bicho[2]);
bicho[2] = 140;
Console.WriteLine("Peso: " + bicho[2]);
- Interfaces só possuem as assinaturas dos métodos. Não possuem propriedades, não dá para declarar ou atribuir variável, não pode ter construtor ou destrutor, não define membros static ou método operator. Muito parecido com classe [static](#Tipos Classe).
public interface Veiculo {
- Toda classe que usar uma interface precisa obrigatoriamente implementar seus métodos.
- Uma classe pode herdar múltiplas interfaces
class Carro:Veiculo, Combate{
- Se definir a herança mas não implementar: dá erro.
error CS0535: 'Carro' não implementa o membro de interface 'Veiculo.ligar()'
- Pode ser implementado e não executar nenhum comando
public void info() {}
- Utilidade (exemplo): somente algumas herdeiras de uma classe vão ter determinado método da classe pai. Como não dá para usar polimorfismo (pois se aplica a todas as filhas) .... CONTINUE
- Métodos declarados dentro de uma interface nunca têm implementação e sempre são públicos.
- Estrutura é um tipo especial que permite o armazenamento de diferentes tipos de dados. É mais simples e se parece com classe.
- Como não é classe, não pode herdar nem servir como base
- Mas pode ter construtores
- Construtor vai ser chamado desde que o operador new seja usado na instanciação do objeto (como já sabemos)
- Tipo valor, e não referência
struct Carro {
Carro c1; // sem chamar o construtor
c1.marca = "Nissan" // nesse caso marca é public
Carro c2 = new Carro("Nissan ", "Versa rebaixado ", "Azul ");
// chamando o construtor
- Quando quer criar vários objetos de um mesmo tipo (Struct é um tipo)
- Isso não serve para classes.
Carro [] concessionaria = new Carro[4];
concessionaria[0].marca = "HRV";
concessionaria[0].cor = "Prata";
voltar nessa aula, entendi pouca coisa 😢
return new Ovo(numOvo, nomeGalinha); // chama o construtor
- Os métodos devem ter parâmetros diferentes (em número ou tipo).
- Funções de mesmo nome que fazem coisas diversas.
public double soma(params double[]n) {
double soma = 0;
foreach (double i in n) {
soma += i;
}
return soma
}
public int soma(params int[]n) {
int soma = 0;
for (int i = 0; i < n.Length; i++) {
soma += n[i];
}
return soma;
}
- Função recursiva: que chama ela mesma. Precisa-se de uma condição de parada.
- Fatorial e somatório: exemplos clássicos
- Substitui estruturas de repetição.
public int fat(int n) {
int res;
if (n <= 1) {
res = 1; // controle de parada
} else {
res = n * fat(n - 1); // modificação de n
}
return res;
}
- Não estão necessariamente em uma classe static
- Acessar os métodos da classe sem precisar declarar um objeto.
- Podem ser chamado de qualquer lugar (se forem públicos)
class Mat {
public static double pi = 3.14;
public static int dobro (int n) {
return n * 2;
}
}
class Aula49 {
static void Main() {
double vPi = Mat.pi; // propriedade
int vinte = Mat.dobro(10); // função
}
}
- É um objeto que faz referência a métodos
- Ex.: uma classe com vários métodos
static
e umdelegate
que faz referência a eles. delegate
possui o endereço de entrada do método, não a rotina inteira- desafio: fazer o mesmo programa com params
using System;
delegate int Op(int num1, int num2);
class Matematica {
public static int soma(int n1, int n2) {
return n1 + n2;
}
public int multi(int n1, int n2) {
return n1 * n2;
}
}
class Aula50 {
static void Main() {
int res;
Op d1 = new Op(Matematica.soma);
res = d1(3, 4);
}
}
- O que eu entendi: cria-se um objeto da "classe" delegate; ele recebe o método pelo parâmetro do construtor, comportando-se como o próprio método. (não entendi a utilidade).
- Usa-se um array, que pode ter qualquer nome;
static void Main(string[] args) { // array
if (args.Length > 0) {
Console.WriteLine("Quantidade de argumentos: " + args.Length);
// ...
- Passando os parâmetros na hora de executar:
.\Aula051-ArgumentosEntrada oi ola sim verdade
Quantidade de argumentos: 4 oi na posição 0 ola na posição 1
//...
- Pergunta: tem que ser string? tem que ser vetor?
- Consegui compilar com int e double, mas deu um warning. Só foi possível passar número inteiro como argumento (nesses dois casos).
- tem que ser vetor, tentei Main(string a, string b) e deu erro.
-
Exceções = erros
-
Toda exceção é representada por uma classe que herda da classe
Exception
-
Em uma zona crítica, é possível definir o caminho caso dê erro (tratamento de erro)
Exceção Sem Tratamento: System.DivideByZeroException: Tentativa de divisão por zero. em Aula52.Main()
- Quando dá problema: executa o que está no
catch
e continua a execução normal do programa.- A continuação se dá a partir do
catch
. Atenção: se ocorrer um erro na primeira linha dotry
, as demais linhas dele não serão executadas, pois o desvio é imediato.
- A continuação se dá a partir do
n1 = 10;
n2 = 0;
try {
res = n1 / n2;
Console.WriteLine("Não deu erro na linha anterior. Ufa!");
} catch {
Console.WriteLine("ERRO!");
}
ERRO! 10 / 0 = 0
- Gerar mensagem:
- Recebe objeto da classe
Exception
- Recebe objeto da classe
/...
} catch (Exception e) { // ou mais específico: DivideByZeroException e
Console.WriteLine("ERRO! " + e.Message);
Console.WriteLine(e);
Console.Writeline(e.GetType)
}
- bloco
finally
: é executado independentemente do disparo da exceção
try {
// executado até a linha do erro
} catch {
// só quando dá erro
} finally {
// executado sempre
}
- E se eu quiser fazer minha própria exceção? Dá para forçar/criar um erro:
throw new Exception(string message);
try {
res = n1 / n2; // aqui não deu erro
Console.WriteLine("{0} / {1} = {2}", n1, n2, res);
throw new Exception ("Encontrei um erro!"); // entra no e.Message
} catch (Exception e) {
//...
- Veja no código da aula a mensagem criada em um método de uma classe.
- throw new Exception("Mensagem") pode estar em qualquer lugar do código
- Controle de escopo.
- Pode-se classificar os elementos dentro do Namespace. Agrupamento de classes por tipo.
- É possível ter duas classes ou funções de mesmo nome mas em namespaces diferentes.
- o local/escopo é diferente
- Na hora de chamar deve-se indicar o namespace
System.Console.WriteLine();
- Boa prática: todas as classes devem ser definidas em um namespace
- Diretiva
using
: traz todas as classes de um namespace para o escopo do projeto- Não é preciso qualificar explicitamente
- Assembly/montagem: classes compiladas em Assemblies - arquivos usualmente com a extensão .dll
- Uma montagem pode conter classes definidas em muitos namespaces, e um namespace pode ocupar vários assemblies
- Para usarmos as classes de um assembly, precisamos adicionar uma referência no projeto, e incluir a diretiva using adequada
- Referência: permite que utilizamos tipos disponíveis em outros Assemblies
namespace Calc1 {
class Area{
}
}
namespace Calc2 {
class Area {
}
}
class Aula54 {
static void Main() {
area = Calc1.Area.Quad(0, 5F); // teve que indicar o namespace
}
}
-
Coleção de dados que são relacionados pelas chaves
-
Quantidade de itens específica/genérica
-
Tem que importar a biblioteca
System.Collections.Generic
using System;
using System.Collections.Generic;
- Construtor genérico:
Dictionary <tipoChave, tipoDado> nome = new Dictionary <tipoChave, tipoDado> ();
Dictionary <int, string> veiculos = new Dictionary <int, string> ();
- Adicionar elementos
nomeDicionario.Add(chave, valor);
veiculos.Add(5, "Aviao");
- Propriedade count (não é método)
veiculos.Count; // tipo int
- Método clear
veiculos.Clear(); // limpa tudo
- Verificar se determinada chave ("posição") está preenchida:
dictionary.ContainsKey(key)
- Lembrar que o preenchimento do dicionário não precisa ser sequencial. Usar as chaves 10, 32 e 150 não vincula os valores ignorados. Lembrar que é um índice, não precisa ser numérico, isso aqui não é array.
if (veiculos.ContainsKey(20)){ // retorna booleano (e não o valor)
- Se existe um valor na coleção:
dictionary.ContainsValue(value)
if (veiculos.ContainsValue("Navio")) { // retorna booleano (e não a chave)
- Remover um valor específico: método
dictionary.remove(chave)
veiculos.Remove(20);
- Propriedades Keys e Values retornam coleções com chaves e valores, respectivamente. Precisa de um elemento Keycollection
- Substituir um valor (também me parece um substituto de dicionario.Add(chave, valor);
dicionario[chave] = valor;
veiculos[15] = "Bicicleta";
- For ou foreach para imprimir todos os elementos de uma coleção
foreach (string v in veiculos) { // não rola pois string não é o tipo da coleção
Console.WriteLine(v);
}
foreach (KeyValuePair<int, string> v in veiculos) {
Console.WriteLine(v.Value); // ainda precisa indicar se quer a chave ou o valor.
}
foreach (string v in veiculos.Values) { // o mais fácil
Console.WriteLine(v);
}
- Outra forma de imprimir
- Todos os elementos estão no valores, que é do tipo ValueCollection
Dictionary <int, String>.ValueCollection valores = veiculos.Values;
foreach string v in valores {
Console.WriteLine(v);
}
- Observação: às vezes usa-se Key/Value no plural, às vezes no singular. Observe o contexto: refere-se a somente um valor específico ou a todos do dicionário?
- Cada elemento é um nó da lista, que tem os links para os elementos posterior e anterior
- Vou chamar de lista2 para não confundir com List (próxima aula)
- Lembrar do
using System.Collections.Generic;
LinkedList<tipoLista2> nomeLista2 = new LinkedList<tipoLista>();
LinkedList<string> transporte = new LinkedList<string>();
lista2.AddFirst(valor);
- Adiciona o valor no início. Ou seja, o último a ser adicionado é o primeiro a ser impresso.
lista2.AddLast(valor);
- Adiciona no final;
transporte.AddFirst("Carro");
transporte.AddLast("Aviao");
06:50 12/10/2020
lista2.AddAfter(node, value), lista.AddBefore(node, value);
LinkedListNode<string> no;
no = transporte.FindLast("Navio"); // .FindLast(valor) renorna um nó de lista encadeada
transporte.AddAfter(no, "Charrete");
transporte.AddBefore(no, "Patinete");
node.Next; node.Previous; node.Value
no = transporte.FindLast("Motocicleta").Next; // no = valor seguinte à motocicleta
Console.WriteLine(no.Value);
Console.WriteLine(no.Previous.Value); // "Motocicleta"
lista2.Remove(value), RemoveFirst(), RemoveLast(), Clear()
lista2.Remove(valor); // valor específico
lista2.RemoveFirst(); // primeiro
lista2.RemoveLast(); // último
lista2.Clear(); // apaga tudo
- Imprimir os elementos (mais fácil que dicionário)
foreach (string v in transporte) {
Console.WriteLine(v);
}
lista2.Find(value)
- Retorna a referência se existir ou
null
se não existir;
- Retorna a referência se existir ou
if (transporte.Find("Carro") == null) {
Console.WriteLine("Não encontrado");
} else {
Console.WriteLine("Elemento encontrado");
}
- Eu chamei o LinkedList anterior de lista, mas entenda que ele é diferente de List
- Usada para substituir o array tradicinal. Mais versátil, mais fácil de trabalhar. Possui vários métodos. "Array tunado"
- Não esquecer do
using System.Collections.Generic;
List<string>carros = new List<string>();
lista.Add(valor)
- obs.: testar se o add funciona com LinkedList
veiculos.Add("HRV");
lista_recebe.AddRange(lista_envia);
veiculos.AddRange(carros); // copia todos os elementos da lista carros para veiculos
lista.Clear();
lista.Contains(valor)
;- retorna true ou false
if (carros.Contains(valor)) {
lista_envia.CopyTo(array_destino, pos_array_destino);
- O destino não pode ser outra lista (pelo menos foi o que eu percebi), e sim um array.
- CopyTo copia todos os elementos da lista para o array, a partir da posição indicada deste.
string [] carros2 = new string[10];
carros.CopyTo(carros2, 2); // pos 0 e 1 ficarão com seus valores de antes
lista.IndexOf(valor);
- retorna a posição da primeira ocorrência ou -1 (se não encontrar)
Console.WriteLine("Está na posição " + carros.IndexOf(valor));
- Impressão dos itens é igual
LinkedList
foreach (string x in carros) {
Console.WriteLine(x);
}
lista.Insert(pos, valor);
carros.Insert(1, "Cruze");
lista.LastIndexOf(valor);
carros.Add("HRV");
int ultimo = carros.LastIndexOf("HRV");
lista.Remove(valor);
elista.RemoveAt(posicao);
carros.Remove("Argo");
carros.RemoveAt(0);
lista.Reverse();
carros.Reverse(); // simplesmente inverte
lista.Sort();
- Ordem alfabética ou numérica
carros.Sort();
lista.Count;
// se não tiver elementos, o resultado é zero
int tamanho = carros.Count // propriedade. É tipo um length
lista.Capacity;
- Quantos elementos cabem na lista. Dá para alterar
- É uma propriedade também
- Diminuir a capacidade para um número menor do que Count dá erro
int cap = carros.Capacity;
carros.Capacity = 15;
- Última aula no modo console, na próxima teremos VS 2019 com janela gráfica 🎉
- Particularidade: o primeiro a ser adicionado é o primeiro a sair. First In, First Out.
- Só dá para visualizar o elemento que está na frente (em primeiro), não é possível manipular os demais
Queue<string>veiculos = new Queue<string>();
- Dá para inicializar passando uma coleção para o construtor (tem que testar se isso funciona para as outras coleções)
string[] vs = {"Carro", "Moto", "Navio", "Aviao"};
Queue<string> veiculos = new Queue<string>(vs);
fila.Enqueue(valor);
// adicionar elementos no final da fila
veiculos.Enqueue("Jegue");
-
fila.Count;
// quantos espaços estão preenchidos -
fila.Contains(valor);
// retorna true ou falseif (comidas.Contains("Bolo")) {
-
fila.Clear();
-
fila.Dequeue();
// retornar e remover elementos do início da fila- Retorna o primeiro elemento da fila e o remove dela
Console.WriteLine("Primeiro veículo: " + veiculos.Dequeue()); //
Console.WriteLine(veiculos.Count); // terá um elemento a menos
fila.Peek()
; // apenas retornar o primeiro- Retorna o primeiro elemento mas não remove.
Console.WriteLine("Primeiro: " + veiculos.Peek());
- Imprimir todos os elementos
- pode fazer com foreach + peek/dequeue ou um foreach normal (abaixo)
foreach (string z in veiculos) {
Console.WriteLine(z);
}
- Mas atenção: Queue não trabalha com indexadores. Não existe:
int c = veiculos[3]
- Só consegue acessar o primeiro elemento da fila.
while (veiculos.Count > 0) {
Console.WriteLine(veiculos.Dequeue);
}
Console.WriteLine(veiculos.Count); // 0
- Ex. de uso: um jogo de cartas em que se retira cartas de um monte.
- Termina aqui o modo console
- Estes foram os pontos principais da linguagem C#. Não é tudo que o que a linguagem faz, faltou muita coisa!
12/10/2020, segunda