Ambientes Virtuais de Execução Estrutura de Tipos 1 Cátia Vaz 2012 Instâncias de Tipos Uma instância de um tipo é um objecto ou um valor. } Um objecto é uma instância de um tipo num garbage collected heap. } As instâncias de um tipo valor não são objectos: } } } 2 Não têm cabeçalho do objecto. Não estão alocados como entidades distintas no garbage collected heap. Cátia Vaz 2012 Membros dos Tipos } Os tipos podem conter membros: } } } De instância De tipo (static) Os membros de um tipo podem ser: } } } } Constantes (membros estáticos) Campos (Fields) Métodos Construtores } } } } } 3 de instância de tipo Propriedades Nested Types (são sempre membros static) Eventos Cátia Vaz 2012 Diferentes tipos de membros - Exemplo public sealed class SomeType { // Nested class private class SomeNestedType { } // Constant, read-only, and static read/write field private const Int32 c_SomeConstant = 1; private readonly String m_SomeReadOnlyField = "2"; private static Int32 s_SomeReadWriteField = 3; // Type constructor static SomeType() { } // Instance constructors public SomeType() { } public SomeType(Int32 x) { } //.... 4 Cátia Vaz 2012 Diferentes tipos de membros - Continuação // Static and instance methods public static void Main() { } public String InstanceMethod() { return null; } // Instance property public Int32 SomeProp { get { return 0; } set { } } // Instance parameterful property (indexer) public Int32 this[String s] { get { return 0; } set { } } // Instance event public event EventHandler SomeEvent; } 5 Cátia Vaz 2012 Outros Membros dos Tipos } Existem outros membros que não fazem parte do CLS } } 6 Sobrecarga de operadores Operadores de conversão Cátia Vaz 2012 Visibilidade de um tipo IL Term C# Term private internal (por omissão) public 7 public Visual Basic Term Descrição Friend Visível apenas dentro do assembly Public Visível dentro e fora do assembly Cátia Vaz 2012 Acessibilidade dos membros de um tipo IL Term Private C# Term private (default) Visual Basic Term Descrição Private Acessível apenas pelos métodos do tipo Protected Acessível apenas pelos métodos do tipo e dele derivados, dentro ou fora do assembly Family and (não Assembly suportada) (não suportada) Acessível apenas pelos métodos do tipo e dele derivados dentro do assembly assembly Friend Acessível apenas pelos métodos de tipos definidos no assembly Family protected internal Family or Assembly protected internal Protected Friend Acessível apenas pelos métodos do tipo e dele derivados dentro ou fora do assembly e pelos métodos de outros tipos do assembly public public Public Acessível por métodos de qualquer tipo 8 Cátia Vaz 2012 Acessibilidade de um membro Para qualquer membro ser acessível, tem de estar definido num tipo que seja visível. } Ao derivar de uma classe base: } } } 9 CLR permite que a acessibilidade de um membro redefinido (overriden) fique menos restritiva. Em C# é necessário que a acessibilidade seja a mesma. Cátia Vaz 2012 Herança } } Um tipo não pode ter mais que uma classe base. Um tipo pode implementar qualquer número de interfaces. IL Term abstract final } C# Term Visual Basic Term Description abstract MustInherit Tipo abstracto sealed NotInheritable Não pode ser estendido. Apenas um dos modificadores pode ser aplicado a um tipo. 10 Cátia Vaz 2012 Classes estáticas (C#) } Não podem ser instanciadas; } O compilador não produz nenhum construtor de instância. Não podem implementar interfaces. } Só podem definir membros estáticos. } O compilador de C# torna este tipo de classes abstract e sealed. } 11 Cátia Vaz 2012 Atributos pré definidos aplicáveis a métodos (1) CLR Term Static Instance Virtual 12 C# Term static (default) virtual Visual Basic Term Descrição Shared Método associado ao próprio tipo, não a uma instância do tipo. Os membros estáticos não podem aceder a campos de instância ou métodos de instância. (default) Método associado a uma instância do tipo. Pode aceder aos campos e métodos de instância, assim como aos campos e métodos estáticos. Overridable O método mais derivado é invocado mesmo que o objecto seja convertido para um tipo base. Aplica-se apenas a métodos de instância. Cátia Vaz 2012 Atributos pré-definidos aplicáveis a métodos (2) CLR Term NewSlot Override C# Term new (default) override Visual Basic Term Descrição Shadows O método não deve redefinir um método virtual definido pelo seu tipo base; o método esconde o método herdado. NewSlot aplica-se apenas a métodos virtuais. Overrides Indica que o método está a redefinir um método virtual definido pelo seu tipo base. Aplica-se apenas a métodos virtuais. Abstract abstract MustOverride Indica que um tipo derivado tem de implementar um método com uma assinatura que corresponda a este método abstracto. Um tipo com um método abstracto é um tipo abstracto. Aplica-se apenas a métodos virtuais. Final sealed NotOverridable Um tipo derivado não pode redefinir este método. Aplica-se apenas ao métodos virtuais. 13 Cátia Vaz 2012 Invocação de métodos em IL - call } A instrução call é utilizada para invocar métodos estáticos, de instância e virtuais } } Quando é usado para invocar um método estático, tem que se especificar o tipo que define o método que o CLR vai invocar. Quando é usado para invocar um método de instância ou virtual, é necessário especificar uma variável que se refere ao objecto. } } 14 o tipo da variável indica que tipo define o método que o CLR deve invocar se o tipo da variável não define o método, os tipos base são verificados para um método correspondente. Cátia Vaz 2012 Invocação de métodos em IL - callvirt } A instrução callvirt pode ser utilizada para invocar métodos de instância ou virtuais. } Quando é usado para invocar um método de instância virtual, o CLR descobre o tipo ctual do objecto que está a invocar o método. } } } 15 Invoca o método polimorficamente. Quando é usado para invocar um método de instância não virtual, o tipo da variável indica o tipo que define o método que o CLR vai invocar. Se a variável que referencia o objecto for null, lança excepção do tipo NullReferenceException. Cátia Vaz 2012 Exemplo 1 using System; public class TesteA{ public static void Main(){ Console.WriteLine( ); Object o = new Object(); o.GetHasCode(); } } .method public hidebysig static void Main() cil managed { .entrypoint // Code size 15 (0xf) .maxstack 1 .locals init (object V_0) IL_0000: nop IL_0001: call void [mscorlib]System.Console::WriteLine() IL_0006: nop IL_0007: newobj instance void [mscorlib]System.Object::.ctor() IL_000c: stloc.0 IL_000d: ldloc.0 IL_000e: callvirt instance int32 [mscorlib]System.Object::GetHashCode() IL_0013: pop IL_0014: ret } // end of method TesteA::Main 16 Cátia Vaz 2012 Exemplo 1 using System; public class TesteA{ public static void Main(){ Object o = new Object(); o.GetType(); } .method public hidebysig static void Main() cil managed { .entrypoint // Code size 15 (0xf) .maxstack 1 .locals init (object V_0) IL_0000: nop } IL_0001: newobj instance void [mscorlib]System.Object::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_000d: pop IL_000e: ret } // end of method TesteA::Main 17 Cátia Vaz 2012 Métodos de instância não virtuais em C# } Em C#, nas chamadas aos métodos de instância não virtuais para tipos referência é utilizada a instrução callvirt } verfica que o objecto que está a fazer esta invocação não é null. Se for lança excepção do tipo NullReferenceException Ex: using System; } public sealed class Program{ public Int32 GetFive() { return 5;} public static void Main( ){ Program p = null; Int32 x = p.GetFive(); } 18 Cátia Vaz 2012 Métodos virtuais – instrução call Por vezes o compilador usa a instrução call para invocar métodos virtuais } Ex: } internal class SomeClass{ public override String toString(){ return base.toString() } } 19 Cátia Vaz 2012 Exemplos using System; class A{ public void F(){ Console.WriteLine("A.F"); } public virtual void G(){ Console.WriteLine( " A.G");} } class B: A{ public void F(){ Console.WriteLine("B.F");} public override void G() { Console.WriteLine("B.G");} } class Test{ static void Main(){ B b = new B(); A a = new B(); a.F(); b.F(); a.G(); b.G(); } } 20 Cátia Vaz 2012 Exemplos using System; class A{ public void F(){ Console.WriteLine("A.F"); } public virtual void G(){ Console.WriteLine( " A.G");} } class B: A{ public void F(){ Console.WriteLine("B.F");} public override void G() { Console.WriteLine("B.G");} } class Test{ A.F B.F B.G B.G static void Main(){ B b = new B(); A a = new B(); a.F(); b.F(); a.G(); b.G(); } } 21 Cátia Vaz 2012 Métodos com número variável de argumentos class TParams { static void showArgs(params object[] args) { foreach(object arg in args) Console.WriteLine(arg.ToString()); } static void Main() { showArgs("olá", "admirável", "mundo", "novo!"); } } Apenas o último parâmetro do método pode ser um parameter array. 22 Cátia Vaz 2012 Passagem de parâmetros: por valor } Passagem por valor: n Através da cópia do conteúdo da variável; n Comportamento por omissão. x = 83 y = addr Caller f(int a, Patient b) “Don” 38 f(x,y) a = 83 b = addr Callee 23 Cátia Vaz 2012 Passagem de parâmetros: por referência } Passagem por referência: n n Através de ponteiro managed para a variável; Em IL indicado por & e em C# por ref. x = 83 y = addr Caller f(ref int a, ref Patient b) “Don” f(ref x, ref y) 38 a = addr b = addr Callee 24 Cátia Vaz 2012 ref versus out using System; using System; public sealed class Program{ public sealed class Program{ public static void Main(){ public static void Main(){ Int32 x; Int32 x = 5; GetVal( out x ); GetVal( ref x ); Console.WriteLine(x); Console.WriteLine(x); } } private static private static void GetVal(out Int32 v){ void GetVal(ref Int32 v){ v = 10; v = 10; } } } } GetVal tem de inicializar v 25 x tem de ser inicializada. Cátia Vaz 2012 Parâmetros ref e a compatibilidade de tipos class Utils { public static void swap(ref object a, ref object b) { object aux=a; a=b; b=aux; } } Sejam duas referências para string: Qual o problema do seguinte código? string s1,s2; Utils.swap(ref s1, ref s2) 26 Cátia Vaz 2012 Construtores } CLR suporta: } Construtores de tipo } } } } Construtores de instância } } 27 Utilizados para estabelecer o estado inicial de um tipo. É um método estático com um nome especial → .cctor. O CLR garante a chamada ao construtor de tipo antes de qualquer acesso a um campo de tipo. Utilizados para estabelecer o estado inicial de uma instância de um tipo. É um método estático com um nome especial → .ctor. Cátia Vaz 2012 Iniciação de tipos } Em CLR, um construtor de tipo pode ser aplicado a interfaces, tipos referência e tipos valor } } } } Não é permitido em C# aplicar construtores de tipos a interfaces. Por omissão os tipos não têm um construtor de tipos definido. Só pode ser definido, no máximo um construtor de tipo por cada tipo. Têm de ser privados } } 28 Em C# a acessibilidade private é colocada automaticamente O método não recebe parâmetros; Cátia Vaz 2012 Iniciação de tipos - Exemplos internal sealed class SomeRefType{ static SomeRefType(){ //. . . } } } internal struct SomeValType{ static SomeValType(){ //. . . } } Os campos com expressões de iniciação na sua definição, são os primeiros a ser iniciados pelo construtor internal sealed class SomeType{ private static Int32 s = 5; static SomeType(){ s = 10; } } . 29 Cátia Vaz 2012 Políticas de iniciação de tipo O CLR garante a chamada ao construtor de tipo antes de qualquer acesso a um campo de tipo; } Políticas de iniciação de tipos: } } } 30 Imediatamente antes do primeiro acesso a qualquer membro – usada em C# quando há construtores de tipo; Em qualquer altura desde que antes do primeiro acesso a um campo de tipo (atributo de Metadata beforefieldinit - política em C# quando não for definido explicitamente um constructor de tipo). Cátia Vaz 2012 Construção de objectos } Quando se cria uma instância de um reference type: } } É reservado, no managed heap, um bloco de memória com o número de bytes necessários para armazenar o objecto do tipo especificado. Inicia os membros overhead do objecto. Cada instância tem associados dois membros adicionais usados pelo CLR na gestão do objecto. } } } } O primeiro membro é um apontador para a tabela de métodos do tipo; O segundo é o SyncBlockIndex (usado na sincronização). É chamado o construtor de instância do tipo. Por fim, devolve uma referência para o objecto criado. Construção de objectos } } O CLR requer que todos os objectos sejam criados usando o operador new } emite a instrução IL newobj. } EX: Employee e = new Employee("ConstructorParam1"); Os construtores de instância nunca são herdados } } Não lhes pode ser aplicado os modificadores virtual, new, override, sealed e abstract Em C#, se uma classe não definir explicitamente um construtor, o compilador gera um por omissão. public class SomeType{ // ... Sem construtor de instâncias } public class SomeType{ public SomeType() : base () { } // ... } Construção de objectos – keyword this private sealed class SomeType{ private Int32 m_x; private String m_s; public SomeType( ){ m_x = 5; m_s= “Ola”; } public SomeType( Int32 x) : this ( ){ m_x = 10; } } } Nota: Embora a maioria das linguagens compilem os construtores de forma a que seja chamado o construtor do tipo base, o CLR não obriga à existência desta chamada. Iniciação de instâncias Construtor de instância: } } } Tem nome especial → .ctor Podem existir várias sobrecargas. Comportamento do construtor: } 1. 2. 3. 34 Inicia os campos que têm expressões de iniciação na sua definição; Chama o construtor da classe base; Executa o seu código. Cátia Vaz 2012 Sobrecarga de métodos } Podem ser sobrecarregados se diferirem em: } } } } } Número de parâmetros; Tipo dos parâmetros; Tipo de retorno; (não em C#) Passagem de parâmetro por valor ou referência. As regras CLS permitem sobrecarga se os métodos diferirem apenas em número ou tipo dos parâmetros. 35 Cátia Vaz 2012 O tipo valor Ponto em C# (com redefinição de Equals) public struct Ponto { public int x, y; public Ponto(int x, int y) { this.x=x; this.y=y; } public override bool Equals(object obj) { if (obj == null) return false; if (!(obj is Ponto)) return false; return Equals( (Ponto) obj); } public bool Equals(Ponto p) { return x== p.x && y == p.y; } public override int GetHashCode() { return x^y; } public override string ToString() { return String.Format("({0},{1})", x, y); } } 36 Cátia Vaz 2012 Desambiguar colisões de nomes } Campos de tipo: } } Campos de instância: } } Através do nome do tipo pretendido. Através do uso das palavras this e base; Métodos: } 2 políticas: } } } 37 Hide-by-name – esconde todos as sobrecargas de métodos com o mesmo nome; (C++) Hide-by-signature – esconde o método com igual assinatura. (C#) Na CLS não existe colisão em nomes que variam apenas na capitalização dos caracteres. Cátia Vaz 2012 Operador new - Exemplo using System; class A { public virtual void F() { Console.WriteLine("A.F"); } } class B: A { public override void F() { Console.WriteLine("B.F"); } } class C: B { new public virtual void F() { Console.WriteLine("C.F"); } } class D: C { public override void F() { Console.WriteLine("D.F"); } } As classes C e D contêm dois métodos com a mesma assinatura! D redefine o método introduzido em C class Test { static void Main() { D d = new D(); B.F B.F D.F D.F A a = d; B b = d; C c = d; a.F(); b.F(); c.F(); d.F(); }} 38 Cátia Vaz 2012 Operador new - Exemplo using System; class A { public virtual void F() {} } class B: A { new private void F() {} // Esconde A.F em B } class C: B { public override void F() {} // Ok, redefine A.F } 39 Cátia Vaz 2012 Atributos aplicáveis a campos IL Term C# Term Visual Basic Term static static Shared initonly readonly ReadOnly Description Campo de tipo Só pode ser iniciado num construtor w O CLR permite que um campo seja marcado como static, initonly ou static e initonly. w O C# suporta a combinação dos dois. 40 Cátia Vaz 2012 Constantes – C# • • • É um símbolo ao qual é atribuído a um valor que nunca se altera. O valor a atribuir tem que ser determinado em tempo de compilação, logo, apenas podem ser definidas constantes de tipos primitivos da linguagem. O compilador guarda o valor da constante na Metadata do módulo (como um campo estático literal) • não é alocada memória em tempo de execução • Não é possível obter o endereço duma constante nem passá-la por referência. • Por levantar problemas de versões, só devem ser usadas quando existe certeza que o seu valor é imutável (p.ex. Pi, MaxInt16, MaxInt32, etc.). • Exemplo em C# • const Int32 SomeConstant 41 = 1; Cátia Vaz 2012 Campos readonly – C# • Campos readonly • Só podem ser afectados durante a construção da instância do tipo onde estão definidos • Um campo static readonly é definido em run time. • Uma constante é definida em compile time. • Em C#: readonly Int32 SomeReadOnlyField = 2; • O campo é marcado com o atributo InitOnly 42 Cátia Vaz 2012 Propriedades As propriedades permitem ao código fonte invocar um método utilizando uma sintaxe simplificada. } Existem dois tipos de propriedades: } } } Propriedades sem parâmetros Propriedades com parâmetros } 43 C# designa as propriedades com parâmetros por indexers. Cátia Vaz 2012 Propriedades sem parâmetros public sealed class Employee{ Employee e = new Employee(); private String m_Name; String empName = e.Name; private Int32 m_Age; e.Age = 41; public String Name { Int32 i = e. Age; get { return( m_Name); } e.Age = -‐5; set { m_Name = value; } } public Int32 Age { get { return( m_Age); } set { if ( value < 0 ) throw new ArgumentOutOfRangeException(“value”, value.ToString(), “O valor tem de ser maior ou igual a 0”); m_Age = value;} } } 44 Cátia Vaz 2012 Propriedades sem parâmetros Cada propriedade tem um nome e um tipo; } Não pode existir sobrecarga de propriedades; } Acedidas através de um nome ou um acesso de membro } Pode ser um membro estático ou de instância } O get accessor de uma propriedade não tem parâmetros } O set accessor de uma propriedade contêm implicitamente o parâmetro value. } 45 Cátia Vaz 2012 Propriedades sem parâmetros - Exemplo 2 public sealed class Employee{ private String m_Name; private Int32 m_Age; private static Int32 nR_Employees; public String Name { get { return(m_Name); } set { m_Name = value; } } public Int32 Age { get { return( m_Age); } set { if ( value < 0 ) throw new ArgumentOutOfRangeException(“value”, value.ToString(), “O valor tem de ser maior ou igual a 0”); m_Age = value;} } public static Int32 NrEmployees{ get { return(nR_Employees); } } 46 Cátia Vaz 2012 Propriedades estáticas e de instância using System; using CTSTester.Properties; namespace CTSTester { namespace Properties { public class TypeWithProps { private static int aTypeField; public string AnInstanceProperty { get { return "instance property"; } } public static int ATypeProperty { get { return aTypeField; } set { aTypeField = value; } } } } class TestProperties { public static void Main() { TypeWithProps mt = new TypeWithProps(); System.Console.WriteLine(mt.AnInstanceProperty); System.Console.WriteLine(TypeWithProps.ATypeProperty); TypeWithProps.ATypeProperty = 30; System.Console.WriteLine(TypeWithProps.ATypeProperty); } } } 47 Cátia Vaz 2012 Propriedades estáticas e de instância (IL de Main) .method public hidebysig static void Main() cil managed { .entrypoint // Code size 45 (0x2d) .maxstack 2 .locals init ([0] class CTSTester.Properties.TypeWithProps mt) newobj instance void CTSTester.Properties.TypeWithProps::.ctor() stloc.0 ldloc.0 callvirt instance string CTSTester.Properties.TypeWithProps::get_AnInstanceProperty() call void [mscorlib]System.Console::WriteLine(string) call int32 CTSTester.Properties.TypeWithProps::get_ATypeProperty() call void [mscorlib]System.Console::WriteLine(int32) ldc.i4.s 30 call void CTSTester.Properties.TypeWithProps::set_ATypeProperty(int32) call int32 CTSTester.Properties.TypeWithProps::get_ATypeProperty() call void [mscorlib]System.Console::WriteLine(int32) ret } // end of method TestProperties::Main 48 Cátia Vaz 2012 Propriedades com parâmetros Identificado pela sua assinatura. } Acedido através de um acesso de um elemento. } Tem de ser um membro de instância. } O get accessor de um indexer tem o mesma lista de parâmetros formais que um indexer. } O set accessor de um indexer tem a mesma lista de parâmetros formais de um indexer, assim como o parâmetro value. } 49 Cátia Vaz 2012 Indexers (criação) class IndexerClass { private int [] myArray = new int[100]; public int this [int index] { get { if (index < 0 || index >= 100) return 0; else return myArray[index]; } set { if (!(index < 0 || index >= 100)) myArray[index] = value; } } } 50 Cátia Vaz 2012 Indexers (Utilização) public class MainClass { public static void Main() { IndexerClass b = new IndexerClass(); b[3] = 256; b[5] = 1024; for (int i=0; i<=10; i++) { Console.WriteLine("Element #{0} = {1}", i, b[i]); } } } 51 Cátia Vaz 2012 Classes parciais – C# } Objectivo: } } } Separar o código gerado automaticamente do código escrito pelo programador Uma classe pode ser dividida em partes, em que cada parte corresponde a uma implementação parcial da classe. Todas as partes da classe devem estar disponíveis no momento da compilação } } 52 gera uma única classe em representação intermédia classe reside num único assembly Cátia Vaz 2012 Classes parciais – C# } Aspectos acumulativos de uma classe: } } } } } } Aspectos não acumulativos: } } } } Campos Métodos Propriedades Indexadores Interfaces implementadas Classe base Tipo-valor ou tipo-referência Visibilidade As diversas partes de uma mesma classe devem concordar nos aspectos não acumulativos. 53 Cátia Vaz 2012 Enumerados } } } Os enumerados permitem definir especializações de tipos integrais que não adicionam campos, mas simplesmente restrigem o espaço de valores de um tipo integral específico. O tipo enumerado é um tipo valor em que o tipo base é System.Enum. Os enumerados têm um segundo tipo subjacente que irá ser usado para a representação dos dados da enumeração } } } } Se não for especificado nenhum, é assumido pelo compilador C# o tipo System.Int32. O Tipo System.Char não pode ser utilizado. Os enumerados pode ser representados em formas boxed e unboxed. Não podem definir métodos, propriedades ou eventos. 54 Cátia Vaz 2012 Enumerados enum EstacoesDoAno { Primavera, Verao, Outono, Inverno }; .class private auto ansi sealed Geometry.EstacoesDoAno extends [mscorlib]System.Enum { .field public specialname rtspecialname int32 value__ .field public static literal valuetype EstacoesDoAno Primavera = int32(0x00000000) .field public static literal valuetype EstacoesDoAno Verao = int32(0x00000001) .field public static literal valuetype EstacoesDoAno Outono = int32(0x00000002) .field public static literal valuetype EstacoesDoAno Inverno = int32(0x00000003) } // end of class Geometry.EstacoesDoAno 55 Cátia Vaz 2012 Exemplo - Continuação using System; internal enum Color{ White, Red, Green, Blue, Orange } public class Program{ public static void Main(){ Console.WriteLine(Color.Format(typeof(Color),3,"G")); Color c = (Color) Enum.Parse(typeof(Color), "White"); Console.WriteLine(c); Console.WriteLine("{0:D} \t {0:G}",c); c = (Color) Enum.Parse(typeof(Color), "white",true); Console.WriteLine(c.ToString("G")); Console.WriteLine(Enum.IsDefined(typeof(Color),"red")); } } 56 Cátia Vaz 2012 Blue White 0 White White False O tipo Enum (excerto) int CompareTo(object target) Compara esta instância com o objecto especificado e retorna uma indicação dos seus valores relativos. static string Format(Type enumType, object value, string format) Converte o valor especificado de um tipo enumerado especificado para a sua representação equivalente sob a forma de string, de acordo com o formato especificado. static string GetName(Type enumType, object value) Retorna o nome da constante na enumeração especificada que tem aquele valor especificado. static string[] GetNames(Type enumType) Retorna um array com os nomes das constantes na enumeração especificada. static Type GetUnderlyingType(Type enumType) Retorna o tipo subjacente da enumeração especificada. static Array GetValues(Type enumType) Retorna um array com os valores das constantes numa enumeração especificada. static bool IsDefined(Type enumType,object value) Retorna true se e só se uma constante com um valor especificado existe numa enumeração especificada. static object Parse(Type enumType,string value) Converte a representação sob a forma de string do nome ou valor numérico de uma ou mais constantes enumeradas para um objecto enumerado equivalente. 57 Cátia Vaz 2012 Interfaces } Keyword interface (para definição de “Interface Types”) } Para especificação de contratos, isto é, conjunto de operações suportadas } As interfaces suportam herança múltipla de outras interfaces. } Não podem conter campos de instância nem métodos de instância com implementação. } Todos os métodos de instância têm, implicitamente, os atributos public e virtual. } Por convenção, o nome das interfaces começa pelo carácter ‘I’ } 58 Exemplos: ICloneable, IEnumerable Cátia Vaz 2012 Exemplo – interface A public interface A{ void GetA(); } .class interface public abstract auto ansi A { .method public hidebysig newslot abstract virtual instance void GetA() cil managed { } // end of method A::GetA } // end of class A 59 Cátia Vaz 2012 Interface IComparable public interface IComparable<T>{ Int32 CompareTo(T other); } public class Point : IComparable<Point>{ private Int32 x,y; public Point( Int32 x, Int32 y){ this.x=x; this.y=y; } public Int32 CompareTo(Point other){ return Math.Sign(Math.Sqrt(x*x+y*y) -‐ Math.Sqrt(other.x*other.x + other.y*other.y) );} } 60 Cátia Vaz 2012 Interfaces } Em C# a implementação de uma interface resulta, por omissão, em métodos sealed. } } O que não acontece se o método na classe for declarado como virtual. Exemplo: } Em C# ¨ } public Int32 CompareTo(Point other){...} Em IL: ¨ .method public hidebysig newslot virtual final instance int32 CompareTo(class Point other) cil managed { 61 Cátia Vaz 2012 Linguagem C# - Excerto do modelo de tipos (interfaces) Legenda Types BCL Namespace System Reference Types User defined Interfaces Object Interface Type ... ValueType ... 62 Cátia Vaz 2012 Interfaces – Exemplo 2 using System; using System.Collections; public class Program{ Porque o tipo do objecto implementa ambas as interfaces public static void Main(){ String s="AVE"; ICloneable cloneable = s; IComparable comparable = s; IEnumerable enumerable = (IEnumerable) comparable; } } 63 Cátia Vaz 2012 Interfaces (pré-genéricos) de enumeração - IEnumerable, IEnumerator e C# foreach public interface System.Collections.IEnumerable { IEnumerator GetEnumerator(); } public interface System.Collections.IEnumerator { Boolean MoveNext(); void Reset(); Object Current { get; } } ArrayList vals = new ArrayList(new Int32[]{ 1, 4, 5 }); IEnumerator itr = vals.GetEnumerator(); ... while(itr.MoveNext()) Console.WriteLine((Int32)itr.Current); ... ArrayList vals = new ArrayList(new Int32[]{ 1, 4, 5 }); foreach(Int32 v in vals) Console.WriteLine(v); 64 Cátia Vaz 2012 ICloneable public interface System.ICloneable { Object Clone(); } w Implementada por tipos que permitam “clonagem” de instâncias w Políticas de “clonagem”: n Cópia superficial (shallow copy) l n 65 Método Object MemberwiseClone() de System.Object Cópia total (deep copy) Cátia Vaz 2012 Interfaces e Value Types w Os Value Types derivam obrigatoriamente e directamente de System.ValueType ou de System.Enum mas podem implementar 0 ou mais interfaces (via boxing) w A conversão entre um Value Type e as interfaces por ele implementadas está sujeita às regras de conversão entre Value Types e Reference Types (boxing e unboxing) public struct Point : System.IComparable { public Int32 CompareTo(Object o) { return ... } } ... Point p1 = new Point(1,2), p2 = new Point(2,1); p1.CompareTo(p2); // boxing em p2 ((System.IComparable)p1).CompareTo(p2); // boxing em p1 e p2 ... 66 Cátia Vaz 2012 Implementação Explícita de interfaces § Uma classe que implementa uma interface pode explicitamente implementar um membro dessa interface. § Quando um membro é explicitamente implementado, não pode ser acedido através uma instância da classe. Exemplo: interface IDimensions { float Length(); float Width(); } class Box : IDimensions { float lengthInches; float widthInches; public Box(float length, float width) { lengthInches = length; widthInches = width; } float IDimensions.Length() { return lengthInches; } float IDimensions.Width() { return widthInches; } public static void Main() { Box myBox = new Box(30.0f, 20.0f); IDimensions myDimensions = (IDimensions) myBox; System.Console.WriteLine("Length: {0}", myDimensions.Length()); System.Console.WriteLine("Width: {0}", myDimensions.Width()); } } 67 Cátia Vaz 2012 Implementação Explícita de interfaces(2) interface IEnglishDimensions { float Length(); float Width(); } interface IMetricDimensions { float Length(); float Width(); } class Box : IEnglishDimensions, IMetricDimensions { float lengthInches; float widthInches; public Box(float length, float width) { lengthInches = length; widthInches = width; float IEnglishDimensions.Length() { return lengthInches; } float IEnglishDimensions.Width() { return widthInches; } float IMetricDimensions.Length() { return lengthInches * 2.54f; } float IMetricDimensions.Width() { return widthInches * 2.54f; } public static void Main() { Box myBox = new Box(30.0f, 20.0f); A implementação explícita de um membro de interface pode ser útil, por exemplo, em cenários de implementação de duas interfaces que partilham métodos com a mesma assinatura IEnglishDimensions eDimensions = (IEnglishDimensions) myBox; IMetricDimensions mDimensions = (IMetricDimensions) myBox; System.Console.WriteLine("Length(in): {0}", eDimensions.Length()); System.Console.WriteLine("Length(cm): {0}", mDimensions.Length()); } 68 } Cátia Vaz 2012 Implementação explícita de Interfaces } Os tipos que implementam as interfaces podem dar uma implementação explícita de alguns métodos da interface. } A implementação explícita é privada public interface IA { void Method1(); void Method2(Int32 val); } 69 public class Impl : IA { public void Method1(){ .. } void IA.Method2(Int32 val){ .. } } Cátia Vaz 2012 Implementação explicita de interfaces } Um tipo exacto (classe) pode optar por esconder a implementação de um método da sua “interface” pública AClass a = new AClass(); a.Draw(); // AClass.Draw IWindow iw = (IWindow) a; iw.Draw(); // IWindow.Draw public interface IWindow { void Draw(); } public interface IArtist[ void Draw(); } public class AClass : IWindow , IArtist { // apenas visivel com uma referência para ICowboy void IWindow.Draw() { } // apenas visível com uma referência para IArtist void IArtist.Draw() { } // visível com uma referência para aClass public void Draw() { } } 70 Cátia Vaz 2012 Implementação explícita de Interfaces (II) A implementação explícita de interfaces permite evitar operações de box e unbox na invocação de métodos de implementação de interfaces em tipos valor, usando o idioma mostrado a seguir: struct Val : ICloneable { public int v; object ICloneable.Clone() { return MemberWiseClone(); } public Val Clone() { return new Val(v); } } 71 Usado quando: ICloneable ic = new Val(5); Val v1 = (Val) ic.Clone(); Permite: Val v = new Val(5); Val v1 = v.Clone(); Sem operações de box e unbox Cátia Vaz 2012 Linguagem C# - Modelo de tipos revisitado Legenda BCL Namespace System Object object User defined String string ValueType Interface Type Class Type Array Array Type Enum Double double Char char Single float Boolean bool Int64 long UInt64 ulong Int32 int UInt32 uint Int16 short UInt16 ushort Sbyte sbyte Byte byte Struct Type Enum Type 72 Cátia Vaz 2012 72 Tabela de métodos } Quando um tipo armazenado no CLR, uma tabela de métodos é inicializada para o tipo. } A tabela de métodos no CLR tem entradas para métodos de instância e estáticos. } A primeira região é usada para os métodos virtuais (declarados no tipo actual, nos tipos base ou interfaces) Slots iniciais irão corresponder aos métodos virtuais declarados pelos tipo base; ¨ Slots seguintes irão corresponder aos novos métodos virtuais introduzidos pelo tipo; ¨ } Exemplo: ¨ } 73 Como System.Object é o tipo base de todos os tipos concretos e tem 4 métodos virtuais, os primeiros slots de todas as tabelas de métodos correspondem a esses 4 métodos A segunda região é usada para métodos não virtuais Cátia Vaz 2012 Atributos de metadata e métodos virtuais Atributos de metadata Presente Ausente virtual O índice na tabela de métodos está na região dos métodos virtuais. O índice na tabela de métodos está na região dos métodos não virtuais. newslot Aloca um novo índice na tabela de métodos Re-utiliza o índice do método do tipo base, se possível. abstract Requere substituição no tipo derivado. Permite substituição no tipo derivado final Proíbe subtituição no tipo derivado. Permite substituição no tipo derivado 74 Cátia Vaz 2012 Tabela de interfaces } Quando um tipo armazenado no CLR, uma tabela de interfaces é inicializada para o tipo. } 75 A tabela de interfaces tem entradas para cada interface que o tipo é compatível Cátia Vaz 2012 Informação de tipo em tempo de execução (RTTI) object reference instância de T2 htype (T2) RTTI Interface table htype (IB) pItfTable campos pBase Method table interface IA { } interface IB { } class T1 : IA, IB { } class T2 : T1, IB { } (T1) RTTI pItfTable Interface table htype (IA) htype (IB) pBase (Object) RTTI Method table pItfTable null pBase Method table baseado no livro “Essential .NET” 76 Cátia Vaz 2012 Arrays } } Todos os tipos de arrays derivam implicitamente da classe abstracta System.Array. Exemplos: } } } } } } } } } } } } 77 Int32[ ] myIntegers = new Int32[100]; Point[ ] myPoints = new Point[10]; Double[ , ] myDoubles = Double[10,20]; int[] numbers = new int[5] {1, 2, 3, 4, 5}; int[] numbers = new int[] {1, 2, 3, 4, 5}; int[] numbers = {1, 2, 3, 4, 5}; int[,] numbers = { {1, 2}, {3, 4}, {5, 6} }; //jagged arrays (arrays de arrays) Point[ ][ ] myPoligon = new Point[3][ ]; myPoligon[0] = new Point[10]; myPoligon[1] = new Point[20]; myPoligon[2] = new Point[30]; Cátia Vaz 2012 Conversão de Arrays } CLR permite a conversão do tipo dos elementos do array origem para o tipo pretendido } } Ambos os arrays têm de ter as mesmas dimensões Tem de existir uma conversão implícita ou explícita do tipo do elemento do array de origem para o tipo do elemento do array destino } } } } FileStream[ ] s1 = new FileStream[10]; Object[ ] o1= s1; FileStream[ ] s2 = (FileStream[ ]) o1; A conversão dos arrays de um tipo para o outro designase por covariância. 78 Cátia Vaz 2012 covariância em arrays Seja o seguinte código: string[] tabStrings = new string[] { "str1", "str2", "str3" }; Console.WriteLine("Size={0}", tabStrings.Length); foreach( string str in tabStrings ) Console.WriteLine(str); // E o código seguinte? object[] tabObjects = tabStrings; // covariância em arrays tabObjects[2]= new object(); // problemas? 79 Cátia Vaz 2012 Arrays com limite inferior diferente de zero } É possível criar este tipo de arrays recorrendo à método: public static Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds) Array unidimensional que contém Um array unidimensional que O tipo do array o limite inferior (o índice de início) contém o tamanho de cada de cada dimensão do array a criar dimensão do array a criar Exemplos: Array a = Array.CreateInstance(typeof(String),new Int32[] {0} , new Int32[] {1}) Array b; b= Array.CreateInstance(typeof(String),new Int32[] {0,0} , new Int32[] {1,1}) 80 Cátia Vaz 2012 Interfaces implementadas pela classe Array interface System.Collections.IList interface System.Collections.ICollection +Add(value:object):int +Clear():void +Contains(value:object):bool +IndexOf(value :object):int +Insert(index:int,value:object):void +Rem ove(value:object):void +Rem oveAt(index:int):void +this(index:int):object +CopyTo(array:Array,inde x:int):void C ount:int S yncRoot:object IsSynchronized:bool IsFixedSiz e:bool IsReadOnly:bool Array interface System.Collections.IEnum erable +Ge tEnume rator():IEnumerator 81 interface System.Collections.ICloneable +Clone():object Cátia Vaz 2012 O tipo Array - propriedades Para além das propriedades relacionadas com a implementação das interfaces IList, IEnumerable e IClonable Length Gets a 32-bit integer that represents the total number of elements in all the dimensions of the Array. LongLength Gets a 64-bit integer that represents the total number of elements in all the dimensions of the Array. Rank Gets the rank (number of dimensions) of the Array. 82 Cátia Vaz 2012 O tipo Array – métodos publicos (I) Para além dos métodos relacionados com a implementação das interfaces IList, IEnumerable e IClonable e dos definidos em object static int BinarySearch(Array, object) Overloaded. Searches a one-dimensional sorted Array for a value, using a binary search algorithm. static void Copy(Array, Array, int) Overloaded. Copies a section of one Array to another Array and performs type casting and boxing as required. static Array CreateInstance(Type, int) Overloaded. Initializes a new instance of the Array class. int GetLength( int dimension) Gets a 32-bit integer that represents the number of elements in the specified dimension of the Array. int GetLowerBound(int dimension) Gets the lower bound of the specified dimension in the Array. 83 Cátia Vaz 2012 O tipo Array – métodos publicos (II) public int GetUpperBound( int dimension) Gets the upper bound of the specified dimension in the Array. public object GetValue(int) Overloaded. Gets the value of the specified element in the current Array. The indexes are specified as an array of 32-bit integers. public void Initialize() Initializes every element of the value-type Array by calling the default constructor of the value type. public static void Reverse(Array) Overloaded. Reverses the order of the elements in a one-dimensional Array or in a portion of the Array. public void SetValue(object, int) Overloaded. Sets the specified element in the current Array to the specified value. public static void Sort(Array) Overloaded. Sorts the elements in one-dimensional Array objects. Acesso a array não seguro } O acesso a array não seguro permite aceder } } } } A elementos de um objecto array managed (alojado no heap) A elementos de um array que está alojado no unmanaged heap A elementos de um array que está alojado na stack Para alojar um array na stack utiliza-se a instrução stackalloc } Apenas se podem criar arrays unidimensionais, cujo tipo de elementos seja tipo valor, com limite inferior zero (zero-based arrays) } } O tipo valor poderá conter campos de tipo referência É necessário especificar o swich /unsafe ao compilador de C# Acesso a array não seguro – Exemplo 1 //. . . public static void Main(){ StackallocDemo(); } private static void StackallocDemo( ){ unsafe{ const Int32 width = 20 ; Char * pc = stackalloc Char [ width ]; String s =“ Ola Mundo “; for(Int32 index = 0; index <width; index++){ pc[width – index – 1] = (index <s.Length) ? s[index] : ‘.’; } Console.WriteLine(new String(pc,0,width)); } //. . . Acesso a array não seguro – Exemplo 2 //. . . public static void Main{ InlineArrayDemo(); } internal unsafe struct CharArray { public fixed Char Characters[ 20 ]; } private static void InlineArrayDemo( ){ unsafe{ CharArray ca; const Int32 width = 20 ; String s =“Ola Mundo“; for(Int32 index = 0; index <width; index++){ ca.Characters[width – index – 1] = (index <s.Length) ? s[index] : ‘.’; } Console.WriteLine(new String(ca.Characters,0,width)); } //. . . Namespaces e Assemblies } Os namespaces permitem o agrupamento lógico de tipos relacionados. Este mecanismo é usado pelo programadores para localizarem facilmente um determinado tipo. Por exemplo, o namespace System.Collections define o grupo de tipos colecção, e o namespace System.IO define o grupo de tipos relacionados com as operações de I/O. A seguir apresenta-se código que constrói um objecto do tipo System.IO.FileStream e um objecto do tipo System.Collections.Queue: class App { static void Main() { System.IO.FileStream fs = new System.IO.FileStream(...); System.Collections.Queue q = new System.Collections.Queue(); } } // ou using System.IO; // Try prepending "System.IO" using System.Collections; // Try prepending "System.Collections" class App { static void Main() { FileStream fs = new FileStream(...); Queue q = new Queue(); } } Importante O CLR não tem a noção de namespaces. Quando acede a um tipo, o CLR necessita de conhecer o nome completo do tipo e qual o assembly que contém a respectiva definição. Não existe nenhuma relação entre assemblies e namespaces. 88 Cátia Vaz 2012