1 - Escreve um programa em C# que aceite dois inteiros na linha de comandos e imprima no ecrã cinco números aleatórios cujo valor se situe no intervalo entre os dois inteiros dados. Usa para o efeito um objeto da classe Random.
2 - A classe
Stack
(namespace
System.Collections
)
implementa a estrutura de dados
stack/pilha,
na qual a última coisa a ser inserida é a primeira a ser retirada. Objetos do
tipo Stack
podem ser instanciados com o construtor simples
Stack()
.
O método
Push()
coloca um objeto na pilha, enquanto o método
Pop()
retira o último objeto lá colocado. O método
Contains()
verifica se dado objeto existe na pilha.
Cria um programa em C# que apresente um menu ao utilizador com quatro opções:
- Inserir string na pilha
- Remover string da pilha, imprimindo a mesma no ecrã
- Verificar se determinada string existe na pilha
- Sair
O menu deve ser apresentado em ciclo, e o programa só deve terminar quando o utilizador selecionar a opção 4.
Nota: A stack/pilha aqui referida é a estrutura de dados e não a stack (zona de memória) onde os programas colocam as variáveis locais dos métodos e por ai fora.
3 - Dá uma vista de olhos na documentação da classe
Math
(namespace System
).
É possível instanciar objetos desta classe? Porquê?
4 - A classe
Queue
(namespace System.Collections
)
implementa a estrutura de dados
queue/fila,
na qual a primeira coisa a ser inserida é a primeira a ser retirada. Objetos do
tipo Queue
podem ser instanciados com o construtor simples
Queue()
.
O método
Enqueue()
coloca um objeto no fim da fila, enquanto o método
Dequeue()
retira o primeiro objeto lá colocado. O método
ToArray()
copia todos os elementos da fila para um array e devolve esse array.
Cria um programa em C# que apresente um menu ao utilizador com quatro opções:
- Inserir string na fila
- Remover string da fila, imprimindo a mesma no ecrã
- Listar todas as string existentes na fila
- Sair
O menu deve ser apresentado em ciclo, e o programa só deve terminar quando o utilizador selecionar a opção 4.
5 - Considera uma classe chamada Line
com os seguintes membros:
// Construtor que cria uma nova instância de Line com as coordenadas indicadas
public Line(double x1, double y1, double x2, double y2);
// Método que indica se esta linha cruza com a linha indicada no primeiro
// argumento
public bool Cross(Line otherLine);
Escreve um programa que solicite ao utilizador a informação necessária para criar duas linhas e depois apresente no ecrã a indicação se as mesmas se cruzam.
6 - Cria uma classe chamada NPC
com três variáveis do tipo float
(energy,
damage e speed) e uma variável do tipo NPCType
, sendo este último uma
enumeração com três valores: Minion
, Soldier
e Boss
. A classe deve ter
um construtor para inicializar estes quatro atributos, e os seguintes métodos:
TakeHit()
- Diminui a energia do NPC para metade.Die()
- Mata o NPC, colocando energia e velocidade a zero.Faster()
- Aumenta velocidade em 10%.Slower()
- Diminui velocidade em 10%.Hit()
- NPC desfere golpe e este método retorna a potência do golpe, que é igual a damage vezes 1, 10 ou 100 caso oNPCType
sejaMinion
,Soldier
ouBoss
, respetivamente.
Além da classe NPC
, apresenta também o código da enumeração NPCType
, tendo
em conta que esta pode facilitar as contas do método Hit()
.
Apresenta também uma classe Program
com um único método estático Main()
para testar a classe NPC
e os seus métodos.
7 - Cria uma classe chamada CharChecker
com um único método de nome
CharCheck()
. Este método recebe três argumentos: 1) uma string; 2) um
caráter c
; e, 3) um inteiro n
. O método retorna true
caso a string
contenha o caráter c
pelo menos n
vezes seguidas.
Adiciona o método estático Main()
à classe CharChecker
. Este método deve: 1)
solicitar ao utilizador uma string; 2) solicitar ao utilizador o valor de
c
; 3) solicitar ao utilizador o valor de n
; 4) criar uma nova instância de
CharChecker
; 5) invocar o respetivo método CharCheck()
para verificar se o
c
aparece mais de n
vezes seguidas na string; e, 6) indicar no ecrã o
resultado.
8 - Cria uma classe chamada Checker
com um único método de nome Check()
.
Este método recebe dois argumentos: 1) um array bidimensional de int
; e, 2)
um int
. O método retorna true
caso encontre uma linha (horizontal, vertical
ou diagonal) de quatro ou mais inteiros iguais ao 2º argumento, ou false
caso contrário.
Adiciona o método estático Main()
à classe Checker
. Este método deve: 1)
solicitar ao utilizador as dimensões do array; 2) solicitar ao utilizador os
valores do array; 3) solicitar ao utilizador o valor a procurar no
array; 4) criar uma nova instância de Checker
; 5) invocar o respetivo
método Check()
para verificar se o valor a procurar no array aparece em
forma uma linha com comprimento igual ou maior a quatro; e, 6) indicar no ecrã
se essa linha existe ou não.
9 - Nos dois exercícios anteriores faria sentido a respetiva classe e o seu
único método serem static
? Porquê?
10 - Cria uma classe chamada Car
com três variáveis de instância, speed
(float
), weight (float
) e fuelType (enumeração Fuel
com 4 valores
possíveis: Gasoline
, Diesel
, LPG
e Electric
). A classe deve ter ainda
uma variável de classe (estática) chamada maxSpeed (float
), com valor por
omissão igual a 220.0f. A classe deve ter um único construtor que aceita
argumentos para inicializar as variáveis weight e fuelType, inicializando
a variável speed a zero. A classe deve ter os seguintes métodos:
Accelerate(float x)
- Aumenta a velocidade com o valor indicado na variávelx
, mas nunca acima de maxSpeed. Devolve a nova velocidade.Break(float x)
- Diminui a velocidade com o valor indicado na variávelx
, mas nunca abaixo de zero. Devolve a nova velocidade.GetSpeed()
- Retorna o valor atual da velocidade sem a alterar.GetFuelType()
- Retorna o tipo de combustível.GetWeight()
- Retorna o peso do carro.GetMaxSpeed()
eSetMaxSpeed()
- Métodos estáticos para obter e definir o valor da variável de classemaxSpeed
.
Cria ainda uma classe chamada TestCar
contendo um método estático Main()
para testar exaustivamente todos os métodos da classe Car
.
11 - Modifica todos os tipos criados no exercício anterior (Car
, Fuel
e
TestCar
) de modo a que façam uso de propriedades e sintaxe de inicialização
de objetos com propriedades. Qual é a versão com menos código boilerplate?
12 - Cria uma classe chamada Dog
. Instâncias desta classe devem ter os
seguintes atributos:
- Peso (
double
) - Altura (
double
) - Cor (
string
) - Saciação (
double
entre 0 e 1, que corresponde à percentagem de saciação)
Instâncias desta classe devem ter a seguinte funcionalidade:
- Comer (no máximo até estar cheio/saciado)
- Fazer necessidades (no mínimo até estar vazio/cheio de fome)
- Ladrar (deve ser impresso o tipo de ladrar)
- Correr (deve ser devolvida a velocidade, igual a saciação * 100 / peso)
A classe deve ser implementada com as variáveis de instância, propriedades,
construtores e métodos necessários para atingir estes requisitos, usando as
melhores práticas para o efeito. Dentro do possível as propriedades devem ser
públicas com valores por omissão, auto-implementadas e com set
privado
(read-only). Todos os nomes usados devem estar em inglês.
Cria também uma classe Program
com um método Main()
estático para testar
todas as funcionalidades da classe Dog
.
As classes Dog
e Program
devem ser completamente documentadas com
comentários XML em inglês.
Este enunciado é propositadamente vago e os alunos devem complementar o exercício da forma que acharem melhor, desde de que vá ao encontro do que é pedido.
13 - Explica por palavras tuas o significado dos seguintes termos:
- Classe
- Objeto / instância
- Método
- Construtor
- Variável de instância
- Propriedade
- Variável de suporte
- Variável local
- Overloading
- Encapsulação
14 - Cria uma classe estática chamada Program
com um único método estático
Main()
. Neste método devem ser solicitadas ao utilizador as coordenadas x
,
y
e z
de um vetor 3D, devendo depois o método mostrar o comprimento do
vetor.
Para a resolução deste exercício é obrigatório usar um tipo anónimo, sem variáveis intermédias, para guardar as coordenadas do vector.
15 - As enumerações, tipo enum
, são tipos de referência ou valor?
16 - Indica duas das principais diferenças entre structs e classes.
17 - Em que parte da memória são colocadas as variáveis do tipo struct quando guardadas num array? Porquê?
18 - Estuda, analisa e executa o projeto 18. Considerando que as structs são tipos de valor, explica a razão de neste caso a alteração de campos de uma struct dentro de um método também se repercutir fora do método.
19 - Explica porque razão as structs não podem ter o valor null
.
20 - Explica o que são tipos imutáveis e quais são as vantagens dos mesmos. Dá um exemplo (em código) de um tipo imutável.
21 - Explica por palavras tuas o significado e/ou para que servem os seguintes conceitos e keywords:
- Herança
- Classe base/superclasse
- Classe derivada/subclasse
- Keyword
is
- Keyword
as
- Keyword
protected
- Keyword
sealed
22 - Considera a seguinte classe e indica, justificando, se a mesma é imutável ou não.
public class Map
{
public float Width { get; }
public float Height { get; }
public int NumberOfBosses { get; }
protected ulong highScore;
protected string name;
public Map(float width, float height, int numberOfBosses, ulong highScore, string name)
{
Width = width;
Height = height;
NumberOfBosses = numberOfBosses;
this.highScore = highScore;
this.name = name;
}
}
23 - Considera o seguinte código:
public struct Bullet
{
private float calibre;
public float Calibre
{
get { return calibre; }
set { if (value < 0.1f) calibre = 0.1f; else calibre = value; }
}
}
public class Weapon
{
public float Value { get; }
public Weapon(float value) { Value = value; }
}
public class Gun : Weapon
{
private Bullet[] bullets;
public Gun(float value, int numBullets, float calibre) : base(value)
{
bullets = new Bullet[numBullets];
for (int i = 0; i < numBullets; i++)
{
bullets[i] = new Bullet() { Calibre = calibre };
}
}
}
a) Escreve uma linha de código que: a) crie uma instância de Gun
com valor
(value
) 50.0 e três Bullet
s de calibre 0.5; e, b) guarde essa instância
numa variável do tipo Weapon
.
b) Adiciona uma propriedade à classe Gun
chamada NumberOfBullets
, só de
leitura, que retorne o número de Bullet
s existentes numa instância de Gun
.
24 - Considera o seguinte código:
public struct Passenger
{
private double weight;
public double Weight
{
get { return weight; }
set { if (value < 5) weight = 5; else weight = value; }
}
}
public class Vehicle
{
public double Value { get; }
public Vehicle(double value) { Value = value; }
}
public class Car : Vehicle
{
private Passenger[] passengers;
public Car(double value, int numPassengers, float avgWeight) : base(value)
{
Random r = new Random();
passengers = new Passenger[numPassengers];
for (int i = 0; i < numPassengers; i++)
{
passengers[i] = new Passenger()
{
Weight = avgWeight + r.Next(-10, 10)
};
}
}
}
a) Escreve uma linha de código que: a) crie uma instância de Car
com valor
(value
) 2550.0 e três Passenger
s com peso médio (avgWeight
) 70; e, b)
guarde essa instância numa variável do tipo Vehicle
.
b) Adiciona um método à classe Car
chamado GetTotalWeight()
que retorne o
peso total dos passageiros numa instância de Car
.
25 - Cria uma nova solução em Visual Studio com as seguintes classes:
- Classe abstrata
Character
com:- Propriedade read-only
Name
do tipostring
- Método
Move()
abstrato, que retorna umchar
indicando a direção seguida ('N'
,'S'
,'W'
ou'E'
)
- Propriedade read-only
- Classe
NPC
, estendeCharacter
, com:- Método
Move()
sobreposto que retorna direção aleatória
- Método
- Classe
Player
, estendeCharacter
, com:- Método
Move()
sobreposto que retorna direção após solicitar a mesma ao jogador através das teclas W, S, A e D
- Método
- Classe
Program
com métodoMain()
para testar as classes anteriores
26 - Indica, justificando, se as seguintes afirmações são verdadeiras ou falsas:
- O polimorfismo permite que classes derivadas ofereçam implementações alternativas de métodos na classe base
- A keyword
override
indica que um método na subclasse é uma extensão/sobreposição de um método na superclasse - A keyword
new
indica que um método na subclasse é uma extensão/sobreposição de um método na superclasse - Métodos
abstract
podem existir em classes não-abstract
- Métodos não-
abstract
podem existir em classesabstract
- Subclasses podem sobrepor métodos
virtual
da superclasse - Subclasses podem sobrepor métodos
abstract
da superclasse - Numa subclasse é possível sobrepor (
override
) um método não-virtual
e não-abstract
da superclasse
27 - Responde às seguintes questões sobre interfaces e herança:
- Qual a keyword para declarar uma interface?
- Qual é a visibilidade dos membros de uma interface?
- Uma classe que implementa uma interface tem de fornecer implementações de todos os membros da interface?
- Uma classe que implementa uma interface pode ter membros que não estão definidos na interface?
- Uma classe pode estender mais do que uma classe base?
- Uma classe pode implementar mais do que uma interface?
- As structs podem implementar interfaces?
28 - Qual a diferença prática entre as keywords override
e new
na
declaração de um método? Dá um exemplo.
Nota: se o exemplo for retirado de algum lado não te esqueças de incluir a
referência.
29 - Escreve o código de uma classe que contenha:
- Uma variável de instância só de leitura
- Uma propriedade (de instância) só de leitura
- Uma variável de classe só de leitura
- Uma propriedade de classe só de leitura
- Um construtor que inicialize as variáveis/propriedades relevantes
A classe deve ser adequadamente comentada, com explicações ou descrições sobre o que cada linha de código faz ou representa.
30 - Considera um projeto com as seguintes classes:
public class Tree
{
private string type;
private float height;
public Tree(string type, float height)
{
this.type = type;
this.height = height;
}
}
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(new Tree("Pinetree", 5.5f));
}
}
Responde às seguintes questões:
- O que é impresso quando o projeto é executado?
- O que é necessário fazer para que seja impresso um valor personalizado quando "imprimimos" uma instância de determinado tipo?
- Adiciona o código necessário à classe
Tree
de modo a que, ao ser impressa uma instância da mesma, seja possível observar o tipo e a altura da árvore.
31 - Considera o seguinte código:
public abstract class GameObject
{
public float X { get; protected set; }
public float Y { get; protected set; }
public abstract int Priority();
public virtual bool IsActive() { return true; }
}
public class Trap : GameObject
{
public override int Priority() { return int.MaxValue; }
public void DisableTrap() { Console.WriteLine("Trap is now disabled."); }
}
public interface ITaggable
{
string Tag { get; set; }
}
Responde às seguintes questões (neste exercício aceitam-se soluções separadas a cada uma destas questões):
- Apresenta o código da classe
PowerUp
que estendeGameObject
e implementa a interfaceITaggable
. A prioridade deve ser igual ao comprimento da tag. Deves sobrepor o métodoIsActive()
de modo a retornefalse
se a tag fornull
ou com comprimento igual a zero, etrue
caso contrário. - Sobrepõe o método
ToString()
na classePowerUp
de modo a que devolva uma string que incluaX
,Y
eTag
. Os números reais devem aparecer com 2 dígitos significativos. - Se
armorPack
for uma instância da classePowerUp
, qual a instrução que define o valor da sua tag como "Armor+75"? - Indica, justificando, quais das seguintes instruções são válidas e quais são inválidas. As instruções são independentes umas das outras, e naquelas que não implicam criação de objetos presume-se que o(s) objeto(s) em questão já foram instanciados. Assume que todas as instruções ocorrem fora das classes discutidas até ao momento.
// Instrução 1
PowerUp pu = new PowerUp();
// Instrução 2
GameObject go = new GameObject();
// Instrução 3
Trap t = new Trap();
// Instrução 4
ITaggable it = new ITaggable();
// Instrução 5
go.DisableTrap(); // go é uma variável do tipo GameObject
// Instrução 6
PowerUp armorPack = new GameObject();
// Instrução 7
int p = gobj.DisableTrap; // gobj é do tipo Trap
// Instrução 8
Console.WriteLine($"{trap.Tag}"); // trap é uma instância de Trap
// Instrução 9
GameObject go = new Trap();
// Instrução 10
GameObject go = new PowerUp();
// Instrução 11
Console.WriteLine($"{pup.Priority()}"); // pup é uma instância de PowerUp
32 - Quais as diferenças entre as coleções não-genéricas e as coleções genéricas no C#? Quais as vantagens destas últimas?
33 - O C# providencia um conjunto bastante completo de coleções genéricas. Algumas das mais usadas são as que se seguem:
Responde às seguintes questões:
- Qual a interface genérica comum a todas estas coleções? Que comportamento ficam as classes obrigadas a ter devido a implementarem essa interface?
- Explica sucintamente como estas coleções funcionam e dá exemplos onde cada uma seja especialmente útil.
- Além das coleções mencionadas, existem mais coleções genéricas no namespace System.Collections.Generic. Dá o exemplo de uma, explica sucintamente como funciona e dá um exemplo onde a mesma possa ser especialmente útil.
34 - Estás a desenvolver um jogo, e tanto o jogador como os NPCs, representados
de forma abstrata pela classe GameCharacter
, transportam itens do tipo
IGameItem
. Os itens de cada GameCharacter
estão guardados numa coleção
genérica do tipo
HashSet<T>,
representada pela variável de instância items
. Alguns destes itens podem
implementar a interface IBurnable
, representada pelo seguinte código:
public interface IBurnable
{
float PotentialEnergy { get; }
void Burn();
}
Escreve um método chamado GetPotentialEnergyOfBurnableItems()
, pertencente à
classe GameCharacter
, que devolve a soma da energia potencial de todos os
itens queimáveis transportados pelo jogador ou por um NPC.
35 - Considera o seguinte tipo:
public struct GameMap
{
private float topScore;
private int gamesPlayed;
private int gamesWon;
public string Name { get; }
public string Filename { get; }
public float SuccessRate
{
get {
if (gamesPlayed == 0)
return 0f;
else
return gamesWon / (float) gamesPlayed;
}
}
public float TopScore {
get
{
return topScore;
}
set
{
if (value > topScore)
{
topScore = value;
}
}
}
public GameMap(string name, string filename)
{
Name = name;
Filename = filename;
gamesPlayed = 0;
gamesWon = 0;
topScore = 0;
}
public void GamePlayed(bool won)
{
gamesPlayed++;
if (won)
{
gamesWon++;
}
}
}
Responde às seguintes questões relativas ao tipo apresentado:
- O tipo apresentado é de valor ou referência? Justifica a tua resposta.
- Identifica as variáveis de instância e explica o seu propósito.
- Identifica as propriedades auto-implementadas.
- Identifica as propriedades só de leitura.
- Identifica os construtores.
- Identifica os métodos de instância.
- Escreve a documentação XML apropriada para a classe e respetivos membros.
- Escreve um método
static
que recebe um iterável deGameMap
e imprime uma tabela bem formatada com informação sobre os mesmos, tal como representado na seguinte figura:
Name Filename Sucess Rate Top Score
--------------------------------------------------------
Hell hell.map 30.2 % 5069.921
Beach beach.map 44.0 % 2231.887
Valley valley.map 72.1 % 131.090
Work work.map 44.4 % 2334.114
School school.map 11.5 % 40.587
Graveyard graveyard.map 69.8 % 1631.103
Mars mars.map 92.1 % 2257.178
36 - Cria uma struct
imutável, de nome Duration
, que representa um
intervalo de tempo, tendo as seguintes propriedades: Seconds
, Minutes
,
Hours
, Days
, Weeks
e Years
. Cria também um programa para testar
diferentes instâncias desta struct
, e responde às seguintes questões:
- Quais são as vantagens desta
struct
ser imutável? - Podemos usar a sintaxe de inicialização de objetos com propriedades para
inicializar instâncias desta
struct
? Porquê?
37 - Considera a seguinte classe:
public abstract class NPC
{
public float HP { get; protected set; }
public NPC(float hp)
{
HP = hp;
}
public void PlayTurn()
{
if (FindEnemies())
{
AttackEnemies();
}
if (FindFood())
{
EatFood();
}
Move();
}
protected abstract bool FindFood();
protected abstract bool FindEnemies();
protected abstract void EatFood();
protected abstract void AttackEnemies();
protected virtual void Move()
{
Console.WriteLine(this.GetType() + " has moved!");
}
}
Responde às seguintes questões:
- É possível instanciar esta classe? Porquê?
- É possível estender esta classe? Porquê?
- Que métodos desta classe podem ser sobrepostos (overridden)? Porquê?
- Que métodos desta classe não podem ser sobrepostos (overridden)? Porquê?
Este exercício continua no problema 8 de UML e design de classes.
38 - Considera a seguinte classe:
public class Texture
{
private string textureFile;
public Texture(string textureFile)
{
this.textureFile = textureFile;
}
}
Cria uma classe chamada PNGTexture
cujo construtor aceita um nome de
ficheiro, invocando o construtor da classe base com o nome de ficheiro
concatenado com a string ".png".
39 - Quais são os requisitos para que uma classe possa ser instanciada usando a sintaxe de inicialização de coleções?
40 - Quais são os requisitos para que uma instância de uma classe possa ser
usada num foreach
como fornecedor de itens?
41 - Considera a seguinte classe:
public class Weapon
{
public float AttackPower { get; }
public float Durability { get; }
public Weapon(float attackPower, float durability)
{
AttackPower = attackPower;
Durability = durability;
}
}
Assume que temos uma lista de armas, ou seja, uma variável do tipo
List<Weapon>
e responde às seguintes questões:
- Faz as alterações necessárias à classe
Weapon
de modo a que quando invocarmos o métodoSort
(ou mais concretamente, o seu overload sem parâmetros) da classeList<T>
, as instâncias deWeapon
fiquem ordenadas porAttackPower
decrescente. Sugestão: a classeWeapon
tem de implementarIComparable<T>
. - Cria uma classe
Program
com um métodoMain()
para testar uma lista de várias instâncias deWeapon
, nomeadamente a sua ordenação porAttackPower
decrescente usando o métodoSort()
sem parâmetros. - O método
Sort
da classeList<T>
tem vários overloads. Um deles,Sort(IComparer<T>)
, permite ordenar a lista usando o critério de ordenação definido numa classe extra. Tal classe, como indicado na assinatura do método, tem de implementar a interfaceIComparer<T>
. Cria uma classe deste tipo cujo critério de ordenação sejaDurability
crescente. - Adiciona ao método
Main()
da classeProgram
um teste à ordenação porDurability
crescente usando o métodoSort(IComparer<T>)
e a classe desenvolvida no ponto anterior.
43 - Considera a seguinte classe:
public class SpaceFleet
{
private Spaceship[] spaceships;
public SpaceFleet() { /* Código do construtor aqui */ }
public Spaceship GetSpaceship(int i)
{
if (i < spaceships.Length)
return spaceships[i];
else
return null;
}
public bool SetSpaceship(int i, Spaceship spaceship)
{
if (i < spaceships.Length && spaceships[i] == null)
{
spaceships[i] = spaceship;
return true;
}
return false;
}
}
- O tipo
Spaceship
é de referência (classe) ou de valor (struct
ouenum
)? Porquê? - A classe está a usar métodos getter e setter. Não seria preferível usar uma propriedade? Justifica a tua resposta.
44 - Considera a seguinte classe:
public class Enemy
{
public static int NumberOfEnemies { get; private set; }
public int Health { get; set; }
public Enemy(int health)
{
NumberOfEnemies++;
Health = health;
}
public void Die()
{
NumberOfEnemies--;
Health = 0;
}
}
Responde às seguintes questões:
- Considera que
monster
é uma instância deEnemy
. Escreve duas linhas de código, uma para imprimir no ecrã a propriedadeHealth
da instância, outra para imprimir a propriedadeNumberOfEnemies
da classe. - Porque razão faz sentido a propriedade
NumberOfEnemies
serstatic
? - De que parte do código pode ser alterado o valor da propriedade
NumberOfEnemies
?
45 - Considera o seguinte código:
public class Power
{
public string Description { get; set; }
public int Range { get; set; }
}
public class PlayerClass
{
private int health;
private int shield;
private List<Power> powers;
public PlayerClass(int health, int shield)
{
this.health = health;
this.shield = shield;
powers = new List<Power>();
}
public void AddPower(Power p)
{
powers.Add(p);
}
}
public struct PlayerStruct
{
private int health;
private int shield;
private List<Power> powers;
public PlayerStruct(int health, int shield)
{
this.health = health;
this.shield = shield;
powers = new List<Power>();
}
public void AddPower(Power p)
{
powers.Add(p);
}
}
Pretende-se que os tipos PlayerClass
e PlayerStruct
implementem a interface
ICloneable
, de
modo a que uma chamada ao respetivo método
IClone()
devolva uma cópia profunda da instância em questão. Uma cópia profunda consiste
numa nova instância cujos campos têm o mesmo valor do objeto original. Se algum
dos campos for um tipo de referência, a instância associada deve também ser
clonada da mesma forma, e por ai fora. Reescreve o código dos tipos
PlayerClass
e PlayerStruct
de modo a que implementem
ICloneable
segundo
estas especificações.
46 - Considera a seguinte classe:
public abstract class GameItem
{
public readonly string name;
public readonly string description;
public GameItem(string name, string description)
{
this.name = name;
this.description = description;
}
}
Responde às seguintes questões:
- Implementa a classe
Sword
que estendeGameItem
, tendo adicionalmente como estado os camposlength
,typeOfMetal
econdition
. O primeiro pode ser representado com um número real, e os outros têm um tipo próprio,TypeOfMetal
eWeaponCondition
, respetivamente. O construtor deSword
aceita 5 parâmetros, que são usados para inicializar todos os campos da classe. No entanto, os campos herdados deGameItem
devem ser inicializados pelo respetivo construtor. - Cria as enumerações
TypeOfMetal
eWeaponCondition
com valores à tua escolha mas de modo a que façam sentido no contexto do problema. - Dá um exemplo em código de como podemos criar uma instância de
Sword
. - Normalmente as variáveis de instância têm visibilidade privada de modo a não comprometer a encapsulação. No entanto não é esse o caso no código apresentado. Porque razão a quebra de encapsulação não é tão grave neste caso?
- Podemos instanciar diretamente
GameItem
? Porquê?
47 - Considera a seguinte interface:
public interface ILightSource
{
double Illuminance { get; }
}
Cria a classe Star
que implementa as interfaces ILightSource
e
IComparable<T>
.
A propriedade Illuminance
da classe Star
é obtida com a seguinte fórmula:
I = d * A * T4
na qual d é a
constante de Stefan–Boltzmann
(com um valor de 5.670 x 10−8), A é a área de superfície da
estrela e T é a temperatura média da estrela. O construtor de Star
aceita
como parâmetros iniciais A e T, que não mudam durante o tempo de vida da
estrela.
O critério de ordenação quando várias instâncias de Star
são ordenadas segue
a área de superfície (decrescente, da maior para a mais pequena), e em caso de
estrelas com a mesma área, a temperatura serve como critério de desempate
(também decrescente).
48 - A API do C# contém uma coleção especializada na manipulação de booleanos (zeros e uns). Faz uma pesquisa para descobrires que coleção é essa e realça algumas das suas principais funcionalidades, nomeadamente vantagens sobre o uso de um simples array de booleanos.
49 - Dá três exemplos de coleções genéricas do C# que implementem
ICollection<T>
.
Qual é ou quais são as funcionalidades que as coleções que implementam esta
interface são obrigadas a ter?
50 - Considera as interfaces
IList<T>
e
IDictionary<TKey,TValue>
.
- Para cada uma das interfaces, dá um exemplo de uma coleção do C# que a implemente.
- Qual é ou quais são as funcionalidades que as coleções que implementam estas interfaces são obrigadas a ter?
51 - Indica três coleções da API do C# que suportem sintaxe de inicialização de coleções e dá um exemplo de uso para cada uma delas.
52 - Considera os tipos MonsterType
e Monster
, definidos pelo seguinte
código:
enum MonsterType { Troll, Ogre, Elf, Demon }
class Monster
{
public const double MaxHealth = 100;
public const int MaxStrength = 200;
public MonsterType Type { get; set; }
public double Health { get; set; }
public int Strength { get; set; }
}
Responde às seguintes questões:
- Existe algum campo
static
(de classe) na classeMonster
? - Adiciona o método iterável
CreateRandomMonsters()
à classeMonster
, que recebe um inteiro n indicando quantos monstros devem ser criados, e que devolve umIEnumerable<Monster>
de n monstros com campos inicializados aleatoriamente (dentro dos limites especificados nos tipos). - O método
CreateRandomMonsters()
deve serstatic
? Justifica a tua resposta. - Faz override do método
ToString()
na classeMonster
de modo a que o mesmo devolva uma string indicando, de forma bem formatada, as várias propriedades do monstro. Por exemplo, a propriedadeHealth
não deve ter mais de duas casas decimais. - Cria a classe
Program
com um métodoMain
para testares a criação de 20 monstros aleatórios com o métodoCreateRandomMonsters()
, imprimindo no ecrã a string devolvida pelo métodoToString()
para cada monstro.
53 - Escreve um programa que comece por solicitar ao utilizador dois conjuntos de números inteiros, conjunto 1 e conjunto 2. O programa deve depois apresentar os resultados das seguintes operações:
- União - Operação de união entre os dois conjuntos, ou seja, elementos presentes no conjunto 1, no conjunto 2, e em ambos os conjuntos.
- Interseção - Operação de interseção entre os dois conjuntos, ou seja, elementos simultaneamente presentes no conjunto 1 e no conjunto 2.
- Diferença - Operação de diferença entre o conjunto 1 e o conjunto 2, ou seja, elementos do conjunto 1 exceto aqueles que também existam no conjunto 2.
- Diferença simétrica - Operação de diferença simétrica entre o conjunto 1 e o conjunto 2, ou seja, elementos que existam ou no conjunto 1 ou no conjunto 2, mas não em ambos os conjuntos.
- Subconjunto - Se o conjunto 1 é um subconjunto do conjunto 2, ou seja, se todos os elementos do conjunto 1 existem também no conjunto 2.
- Superconjunto - Se o conjunto 1 é um superconjunto do conjunto 2, ou seja, se o conjunto 1 contem todos os elementos do conjunto 2.
Os resultados das operações 1 a 4 devem aparecer de forma ordenada, e as operações devem ser independentes umas das outras, partindo sempre dos conjuntos 1 e 2 originais.
Este problema deve ser resolvido com recurso direto às funcionalidades oferecidas pelas coleções do C#.
54 - Em alguns casos os dicionários podem ser usados para fins de caching, ou seja, para guardar resultados obtidos recentemente. Escreve um programa que leia a lista de jogos disponível aqui para um array de strings, e que solicite ao utilizador (em ciclo infinito) uma frase, que será comparada com todos os jogos no array. Para existir um match, basta que uma string que representa o nome de um jogo contenha a frase inserida pelo utilizador. A procura deve ser independente de maiúsculas e minúsculas. Após a procura, o programa deve indicar quantos jogos encontrou e quanto tempo demorou a fazer a procura. O seguinte código apresenta um template da solução:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
class Program
{
static void Main(string[] args)
{
// Abrir ficheiro com nomes de jogos e colocar num array de strings
string[] games = File.ReadAllLines("videogames.txt");
// Ciclo de procuras, infinito
while (true)
{
// Cronómetro
Stopwatch stopwatch;
// String a procurar
string searchString;
// Resultados da procura, têm de ser enumeráveis e contáveis
ICollection<string> results;
// Solicitar string de procura, transformar em minúsculas para
// facilitar comparação mais à frente
Console.Write("Search for? ");
searchString = Console.ReadLine().ToLower();
// Começar contagem do tempo
stopwatch = Stopwatch.StartNew();
// Realizar procura aqui e colocar resultados na variável results,
// que provavelmente será uma lista. A procura deve:
// - Ignorar strings vazias ou que comecem com cardinal #
// (que representa um comentário no ficheiro videogames.txt)
// - Ser independente de maiúsculas e minúsculas
// Parar o cronómetro
stopwatch.Stop();
// Mostrar resultados da procura
Console.WriteLine($"Time to find {results.Count} games was" +
$"{stopwatch.Elapsed}");
// Opcionalmente podemos mostrar alguns ou todos os jogos
// encontrados para fins de debugging
}
}
}
Cada vez que é feita uma procura é necessário percorrer todo o array de jogos novamente. No entanto a tua solução deve primeiro verificar se a procura já foi feita e existe em cache (i.e., num dicionário criado para o efeito). Caso a procura exista em cache, serão devolvidos os resultados previamente guardados. Caso contrário é percorrido novamente todo o array de jogos. Compara o tempo da procura no array para novas procuras com o tempo de procura no dicionário para pesquisas previamente efetuadas.
Sugestão: O dicionário deve ser do tipo Dictionary<string, ICollection<string>>
, em que a chave representa a frase de procura e o valor
representa os resultados dessa mesma procura.
55 - Considera o tipos LootType
e Loot
:
public enum LootType { Health, Ammo, Shield, Weapon, Collectible }
public class Loot
{
public LootType WhatKindOfLootAmI { get; set; }
public string Description { get; set; }
public ulong Value { get; set; }
}
- Faz override dos métodos
GetHashCode()
eEquals()
de modo a que um loot seja considerado único no jogo se tiver o mesmo tipo, nome e valor. Sugestão: Uma forma rápida de obter um hash code para um dado tipo consiste em realizar a operação XOR no hash code dos seus diferentes campos. - Testa a tua solução colocando vários objetos do tipo
Loot
num conjunto, repetindo propositadamente os campos de duas instâncias diferentes. - Se o tipo
Loot
fosse umastruct
qual seria o comportamento por omissão relativamente à igualdade de instâncias? Era necessário ter feito os overrides na primeira alínea do exercício?
56 - Considera a seguinte classe:
public class Problem
{
public static void Main()
{
// Um array de objetos de diferentes tipos
object[] stuff = { "ola", 1, 2.3, 5f, 12L, 4UL, 5U, "bye", 4, 9 };
// Imprimir apenas objetos do tipo int
foreach (int i in Filter<int>(stuff))
{
Console.WriteLine("int = " + i);
}
// Imprimir apenas objetos do tipo float
foreach (float f in Filter<float>(stuff))
{
Console.WriteLine("float = " + f);
}
}
}
Escreve e adiciona o método Filter()
à classe Problem
de modo a que o
código no Main()
faça sentido e funcione.
57 - Escreve um método static
que inicialize e devolva uma
lista genérica
contendo n cópias de um valor passado como parâmetro e tipo especificado como
argumento genérico.
58 - Quais são os requisitos para que uma instância de uma classe possa ser
usada num foreach
como fornecedor de itens?
59 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico tenha um construtor vazio?
60 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico seja um tipo de referência?
61 - Numa classe ou método genérico como podemos inicializar o tipo genérico
com o seu valor por omissão (equivalente a zero ou null
)?
62 - De modo a que o seguinte código passe a funcionar é necessário adicionar algumas linhas antes do mesmo. Quais são?
class Program
{
public static void Main()
{
float number;
WriteLine("Escreve um número: ");
number = ToSingle(ReadLine());
WriteLine("O coseno desse número é {0:f3}", Cos(number));
}
}
63 - O método Next
da classe Random
tem
vários overloads. Explica o que é um overload e descreve as diferenças
entre os vários overloads do método indicado.
64 - Existe uma class Random
tanto na API do C# como na API do Unity, que
podem respetivamente ser importadas com os seguintes using
:
using System;
using UnityEngine;
Responde às seguintes questões:
- Como podemos diferenciar, no nosso código, entre o
Random
do C# e oRandom
do Unity? - Qual a principal diferença entre as duas classes, do ponto de vista de instanciação e invocação dos métodos que produzem números aleatórios?
65 - Considera a classe static
Input
do Unity.
Responde às seguintes questões:
- O que é necessário para que uma classe seja
static
? - Porque razão faz sentido a classe
Input
serstatic
? - O que é necessário fazer para usarmos os métodos e propriedades da classe
Input
diretamente no nosso código, por exemplo, escrevermosGetButton()
em vez deInput.GetButton()
? - Quais são os perigos de usar a abordagem indicada na pergunta anterior.
- Identifica mais duas classes
static
na API do Unity. Discute se faz sentido essas classes seremstatic
.
66 - Considera o seguinte código, altamente abstrato:
public interface IFighter
{
void Fight();
}
public abstract class DarkSideFighter : IFighter
{
public abstract void Fight();
}
public abstract class GoodGuyFighter : IFighter
{
public abstract void Fight();
}
public abstract class FighterFactory
{
protected abstract DarkSideFighter CreateDarkSideFighter();
protected abstract GoodGuyFighter CreateGoodGuyFighter();
}
- Adiciona um método concreto à classe
FighterFactory
que não aceite parâmetros e devolva uma instância deDarkSideFighter
e outra deGoodGuyFighter
, devendo para o efeito invocar os respetivos métodosCreate...Fighter()
. - Desenha o diagrama UML de classes do código.
- Este código corresponde a um design pattern muito comum. Faz uma pesquisa e tenta descobrir qual.
- Considera que
myFighter
é um objeto cuja classe concreta (que desconheces) implementaIFighter
. Identifica o polimorfismo na seguinte instrução:myFighter.Fight();
.
Neste exercício aceitam-se soluções separadas para cada uma das alíneas.
67 - Escreve um método static
que inicialize e devolva um
enumerável genérico
contendo n cópias de um valor passado como parâmetro e tipo especificado como
argumento genérico.
68 - Cria a classe genérica AwesomeList<T>
que estende
List<T>
e faz override
do método ToString()
de modo que a devolva uma string que
indique o número de elementos na lista bem como o tipo desses elementos.
Nota: pode ser necessário recorrer ao operador
typeof
para obter o tipo de T
.
69 - Considera a seguinte classe:
using System.Collections;
using System.Collections.Generic;
public class BasketballTeam : IEnumerable<string>
{
public string Guard { get; set; }
public string ShootingGuard { get; set; }
public string SmallForward { get; set; }
public string PowerForward { get; set; }
public string Center { get; set; }
public IEnumerator<string> GetEnumerator()
{
yield return Guard;
yield return ShootingGuard;
yield return SmallForward;
yield return PowerForward;
yield return Center;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
- Cria uma classe
Program
com um métodoMain
para testar a classe apresentada. Mais concretamente, no métodoMain
deves: a) criar uma instância deBasketballTeam
usando a sintaxe de inicialização de objectos com propriedades; e, b) imprimir no ecrã o nome de todos os elementos da equipa usando o facto da classeBasketballTeam
ser iterável. - Supõe que o C# não tem a declaração
yield return
. Reescreve o métodoGetEnumerator
tendo em conta essa limitação. - Quais são as vantagens óbvias do uso de
yield return
relativamente à forma como reescreveste o código na alínea anterior?
70 - Escreve um método static
que troque o valor de duas variáveis de entrada
cujo tipo é definido em tempo de execução (ou seja, por quem invoca o método).
71 - Cria uma classe IntList
que estende List<int>
, adicionando três versões
de um método que retorne o valor mínimo (int
), o valor máximo (int
) e o
valor médio (float
) referentes aos inteiros contidos na lista. Cada versão do
método deve retornar estes valores de forma diferente: 1) usando parâmetros de
saída (out
); 2) usando uma classe/struct específica; e, 3) usando tuplos. A
segunda forma pressupõe a criação de uma classe ou struct extra; neste caso
podem criar uma classe/struct interna, ou seja, dentro da classe IntList
.
Sobrepõe ainda o método ToString()
de modo a que a string devolvida indique
quantos elementos tem a lista, bem como os valores mínimo, máximo e médio
contidos na mesma.
72 - Cria uma classe chamada HighScoreManager
, que contém internamente uma
coleção com um máximo de 10 Tuple<string, float>
, cada um representando o
nome de um jogador e o respetivo score. Além da coleção referida, a classe
deve ainda conter:
- Um construtor, que aceita opcionalmente um nome de ficheiro (deve existir
um nome por omissão), e:
- Caso o ficheiro não exista, inicializa a coleção sem elementos.
- Caso o ficheiro exista, abre-o e inicializa a coleção de modo a que contenha os nomes e scores especificados no ficheiro.
- Caso o ficheiro exista, mas tenha um formato inválido, lançar uma excepção
do tipo
InvalidOperationException
.
- Um método
AddScore(string name, float score)
, que adiciona um novoTuple<string, float>
à coleção. Se o número de scores ultrapassar 10, o tuplo contendo o menor score deve ser removido. - Um método
Save()
, que guarda os scores no ficheiro especificado no construtor. - Um método
ToString()
, que devolve uma string contendo uma tabela devidamente formatada com todos os nomes e scores, do mais alto ao mais baixo. - Um método iterável
GetScores()
que retorna de forma ordenada (do score mais alto até ao score mais baixo) todos tuplos guardados na coleção.
O formato do ficheiro de high scores fica ao critério dos alunos.
Cria também uma classe Program
com um método Main
para testar os vários
métodos da classe HighScoreManager
.
73 - Cria uma classe, com um único método estático Main()
, que solicita
ao utilizador um número inteiro positivo e apresenta o respetivo número da
sequência de Lucas. O número
deve ser calculado de forma recursiva com uma ou mais funções locais.
74 - Considera o seguinte método:
public void AwesomeMethod(float a, float b, int c = 2, string d = "hi!")
{
Console.WriteLine($"{a} {b} {c} {d}");
}
- Quais os parâmetros obrigatórios?
- Quais os parâmetros opcionais?
- Qual o valor de
a
,b
,c
ed
se método for invocado da seguinte forma:AwesomeMethod(-1.0f, 0.0f, d: "bye!")
? - Qual o valor de
a
,b
,c
ed
se método for invocado da seguinte forma:AwesomeMethod(50, -10, 14)
? - Qual o valor de
a
,b
,c
ed
se método for invocado da seguinte forma:AwesomeMethod(c: 100, b: 123f, d: "yeah!", a: 0)
? - Qual o valor de
a
,b
,c
ed
se método for invocado da seguinte forma:AwesomeMethod(b: 1, a: 2)
?
75 - Cria uma classe estática chamada Stats
com vários métodos utilitários
para determinar estatísticas simples. Cada um destes métodos deve aceitar um
número variável de doubles e retornar o valor estatístico que lhe compete.
Devem existir métodos para a retornar a média, mediana, moda, máximo e mínimo.
Cria também uma classe Program
com um método Main()
para testar os vários
métodos da classe Stats
.
76 - Adiciona dois método à classe criada no exercício anterior:
- O primeiro retorna todas as estatísticas de um número variável de doubles (média, mediana, moda, máximo e mínimo) num tuplo.
- O segundo retorna todas as estatísticas de um número variável de doubles
(média, mediana, moda, máximo e mínimo) em parâmetros
out
.
Ambos os métodos devem fazer uso dos métodos já existentes para cálculo das estatísticas.
Atualiza o método Main()
da classe Program
para testar os dois métodos
novos.
77 - Responde às seguintes questões:
- Nos métodos, os parâmetros opcionais têm de aparecer a seguir a todos os parâmetros obrigatórios?
- Num método, um parâmetro com a keyword
params
tem de ser o último? - Dado o método
void AwesomeMethod(float x, int y = 2, params double[] z) {...}
, quais das seguintes instruções são válidas? Em caso afirmativo, quais os conteúdos dex
,y
ez
?
AwesomeMethod(a: 2.1f, 3, 12, 23f, 34.5, -123.0);
AwesomeMethod(1.7f);
AwesomeMethod();
AwesomeMethod(0.01f, z: new double[] { 2.3, 4, -4f });
AwesomeMethod(0, 2.3f, 2, 3, 4, 5);
AwesomeMethod(-1.9f, 2, 3.0, 4.0, 5.0, 6.0, 19, -1, 4);
78 - Quais as vantagens e desvantagens do uso de out
e ref
na passagem de
parâmetros para métodos?
79 - Qual a diferença entre out
e ref
na passagem de parâmetros para
métodos?
80 - Responde Sim/Não às seguintes questões:
- Um parâmetro
out
indica que foi passada uma referência para a própria variável em vez de uma cópia da mesma? - Um parâmetro
ref
indica que foi passada uma referência para a própria variável em vez de uma cópia da mesma? - Os parâmetros
out
têm de ser inicializados dentro do método? - Os parâmetros
ref
têm de ser inicializados dentro do método?
81 - Escreve um programa que aceita strings escritas pelo utilizador em loop, gravando as mesmas convertidas em maiúsculas num ficheiro especificado como argumento da linha de comandos. O programa termina quando o utilizador insere uma string vazia (isto é, simplesmente pressiona ENTER sem escrever nada).
Sugestão: confere o método ToUpper() da classe string.
82 - Escreve um programa que aceita strings escritas pelo utilizador em
loop e tenta converte-las em byte
. Em caso de sucesso mostra uma mensagem
apropriada contendo o valor convertido. Em caso de falhanço, mostra uma
mensagem com indicação desse facto. O programa termina quando o utilizador
insere uma string vazia (isto é, simplesmente pressiona ENTER sem escrever
nada).
83 - Considera o seguinte programa:
using System;
public class NPC
{
public float HP { get; private set; }
public NPC(float hp) { HP = hp; }
public void TakeHit(float damage)
{
HP -= damage;
if (HP < 0) HP = 0;
}
}
public class Program
{
public static void Main()
{
NPC[] npcs = new NPC[]
{
new NPC(12.5f),
new NPC(19.5f)
};
NPC npc1 = npcs[0];
npc1.TakeHit(5f);
foreach(NPC npc in npcs)
{
Console.WriteLine($"HP={npc.HP}");
}
}
}
Responde às seguintes questões:
- O que é impresso pelo programa? Descreve sucintamente o que acontece no
Main()
. - Se a classe
NPC
passar a ser umastruct
, o que é impresso pelo programa? Porquê? - Que alteração temos de fazer no
Main()
(à parte de manipular o NPC diretamente no array), para podermos alterar o valor do HP do NPC, sendo este umastruct
?
84 - Escreve o código de um método genérico que instancie e devolva um array
de objetos do tipo genérico T
. O tamanho do array e o valor inicial de
todos os elementos do array devem ser passados como argumentos opcionais
do método, cujos valores por omissão são 10 e default(T)
, respetivamente.
Mostra 5 formas diferentes de usar o método (com tipos diferentes,
especificando ou não todos os parâmetros, indicando o nome dos parâmetros,
trocando a ordem dos mesmos, etc).
85 - A classe Array
tem
vários métodos utilitários static
. Um deles tem uma série de overloads que
fazem algo similar ao especificado no exercício anterior. Descobre qual é o
nome deste método e utiliza um dos seus overloads para instanciar uma matriz
(i.e., um array bidimensional) de 50 x 50 booleanos.
86 - Escreve um método chamado Saturate()
que recebe dois inteiros e devolve
um booleano. O primeiro inteiro deve ser positivo e define um limite inferior e
superior dentro do qual o segundo inteiro deve estar. Caso o segundo inteiro
esteja dentro dos limites, o método simplesmente retorna false
. Caso
contrário o método modifica o segundo inteiro, colocando-o dentro dos limites,
devolvendo true
. A modificação do segundo inteiro deve ser visível fora do
método. Alguns exemplos:
1º int |
2º int (original) |
2º int (talvez modificado) |
Valor de retorno |
---|---|---|---|
10 | 23 | 10 | true |
15 | -20 | -15 | true |
5 | -3 | -3 | false |
25 | -22 | -22 | false |
12 | 15 | 12 | true |
Testa o método Saturate()
com diferentes valores de modo a verificares o seu
correto funcionamento. Faz sentido este método ser static
? Porquê?
87 - Escreve um programa que cria uma matriz binária bi-dimensional aleatória
que irá servir de input para uma outra função que retorna uma nova matriz
bi-dimensional de inteiros que consiste na soma de todos os numeros das celulas
vizinhas incluíndo a própria célula. Para este exercício iremos usar o método
de vizinhança de Von Neumann
e do método de vizinhança de Moore
.
É importante considerar que nestes métodos o mundo é Toroidal
,
ou seja "dá a volta" ao início quando chegamos as extremidades (ver figura em baixo).