C# e Programação Genérica Joel Pereira ( [email protected]) Software Design Engineer WinFS API Team Microsoft Corporation 8º Simpósio Brasileiro de Linguagens de Programação Conteúdo Baseado na versão Visual Studio 2005, Community Release – Maio de 2004 Material disponibilizado pelo time C# Anders Hejlsberg Eric Gunnerson Novidades da Linguagem C# Programação Genérica Tipos Nullable Métodos Anonimos Iterators Tipos Parciais Classe Estática Entre outras… Programação Genérica public class List<T> List { private object[] T[] elements; elements; private int count; public void Add(T Add(object element) element) { { if (count == elements.Length) Resize(count * 2); elements[count++] = element; } } public object T this[int this[int index] index] { { get { return elements[index]; } =List(); List intListintList List<int> = new new List<int>(); set { elements[index] = value; } } intList.Add(1); // No Argument boxing is boxed intList.Add(2); // No Argument boxing is boxed public int Count {intList.Add("Three"); // Compile-time Should be an error error get { return count; } } int i = intList[0]; (int)intList[0]; // No Castcast required required Programação Genérica Porque? Verificação de tipos em tempo de compilação Desempenho Redução de código Como é implementado? Instanciado em tempo de execução, não compilação Verificação na declaração, não na instanciação Funciona para tipos referências e valores Informação em tempo de execução Programação Genérica Parametros tipo podem ser especificados para Class, struct, interface, e delegate class Dictionary<K,V> {…} struct HashBucket<K,V> {…} interface IComparer<T> {…} customerLookupTable; delegate RDictionary<string,Customer> Function<A,R>(A arg); Dictionary<string,List<Order>> orderLookupTable; Dictionary<string,int> wordCount; Programação Genérica Parametros tipo podem ser especificados para Class, struct, interface, e delegate Métodos class Utils { public static T[] CreateArray<T>(int size) { return new T[size]; } public static void SortArray<T>(T[] array) { … string[] names = Utils.CreateArray<string>(10); } names[0] = "Jones"; } … Utils.SortArray(names); Programação Genérica Parametros tipo podem ser especificados para Class, struct, interface, e delegate Métodos Parametros tipo podem ter constraints class Dictionary<K,V>: Dictionary<K,V> where IDictionary<K,V> K: IComparable { where K: IComparable<K> public V: where void IKeyProvider<K>, Add(K key, V value) IPersistable, { new() { … public if (key.CompareTo(x) (((IComparable)key).CompareTo(x) void Add(K key, V== value) 0) {…} { == 0) {…} … } } Programação Genérica Constraint Primaria "class", or "struct" Constraint Secondaria Interface ou parametro tipo Constraint de instanciação "new()" class Link<T> where T: class {…} class Nullable<T> where T: struct {…} class Relation<T,U> where T: class where U: T {…} Programação Genérica Collection classes List<T> Dictionary<K,V> SortedDictionary<K,V> Stack<T> Queue<T> Collection interfaces IList<T> IDictionary<K,V> ICollection<T> IEnumerable<T> IEnumerator<T> IComparable<T> IComparer<T> Collection base classes Utility classes Reflection Collection<T> KeyedCollection<T> ReadOnlyCollection<T> Nullable<T> EventHandler<T> Comparer<T> Demo Programação Genérica Tipo Nullable System.Nullable<T> Possibilita que um tipo valor seja null É uma struct que associa um T e um bool public struct Nullable<T> where T: struct { public Nullable(T value) {…} public T Value { get {…} } public bool HasValue { get {…} } … } Nullable<int> x = new Nullable<int>(123); … if (x.HasValue) Console.WriteLine(x.Value); Tipo Nullable Síntaxe T? int? x = 123; double? y = 1.0; Literal null int? x = null; double? y = null; Lifted conversions Lifted operators Operador ?? int i = 123; int? x = i; double? y = x; int? z = (int?)y; int j = (int)z; int? x = GetNullableInt(); int? y = GetNullableInt(); int? z = x + y; int? x = GetNullableInt(); int? y = GetNullableInt(); int z = (x + y) / (x – y) ?? 0; Métodos Anonimos class MyForm : Form { ListBox listBox; TextBox textBox; Button addButton; public MyForm() { listBox = new ListBox(...); textBox = new TextBox(...); addButton = new Button(...); addButton.Click += delegate new EventHandler(AddClick); { } listBox.Items.Add(textBox.Text); }; }void AddClick(object sender, EventArgs e) { } listBox.Items.Add(textBox.Text); } } Métodos Anonimos Permite bloco de código ao inves do delegate Infêrencia automatica do tipo de delegate Bloco de código sem uso de parametros Ou com parametros Em ambos os casos, tipo de retorno deve ser igual button.Click += delegate { MessageBox.Show("Hello"); }; button.Click += delegate(object sender, EventArgs e) { MessageBox.Show(((Button)sender).Text); }; Métodos Anonimos Bloco de código pode acessar variáveis public class Bank { locais public List<Account> class Bank GetLargeAccounts(double minBalance) { { Helper helper = new Helper(); delegate bool Predicate<T>(T List<Account> accounts; item); helper.minBalance = minBalance; return accounts.FindAll(helper.Matches); publicList<Account> class List<T> GetOverdrawnAccounts() { } { return accounts.FindAll(delegate(Account a) { public List<T> FindAll(Predicate<T> filter) { return a.Balance < 0; internal class Helper List<T> });{ result = new List<T>(); foreach (T item double in this) {minBalance; } internal if (filter(item)) result.Add(item); } List<Account> GetLargeAccounts(double internal bool Matches(Account a) { minBalance) { return result; return accounts.FindAll(delegate(Account return a.Balance >= minBalance; a) { } return a.Balance >= minBalance; } } });} }} } Métodos Anonimos Converção de métodos Tipo inferido quando possivel using System; using System.Threading; class Program { static void Work() {…} } static void Main() { Thread t = new Thread(Work); Thread(new ThreadStart(Work)); t.Start(); } Iterators foreach depende “enumerator pattern” Método GetEnumerator() foreach (object obj in list) { DoSomething(obj); Enumerator e = list.GetEnumerator(); } while (e.MoveNext()) { object obj = e.Current; DoSomething(obj); } foreach faz uma enumeração ficar fácil Mas enumeradores são dificeis de escrever! Iterators public class ListEnumerator : IEnumerator { List list; int index; public class List { internal ListEnumerator(List list) { internal object[] elements; this.list = list; internal int count; index = -1; public ListEnumerator}GetEnumerator() { return new ListEnumerator(this); public bool MoveNext() { } int i = index + 1; } if (i >= list.count) return false; index = i; return true; } } public object Current { get { return list.elements[index]; } } Iterators Método que computapublic e retorna uma IEnumerator GetEnumerator() { return new __Enumerator(this); sequência de valores incrementalmente } private class __Enumerator: IEnumerator yield return e yield break { object current; Deve retornar um IEnumerator ou int state; IEnumerable public bool MoveNext() { switch (state) { public class List case 0: … { case 1: … public IEnumerator GetEnumerator() { case 2: … … for (int i = 0; i < count; i++) { } yield return elements[i]; } } public object Current { } get { return current; } } } } Iterators public class List<T> { public IEnumerator<T> GetEnumerator() { for (int i = 0; i < count; i++) yield return elements[i]; } public IEnumerable<T> Descending() { for (int i = count - 1; i >= 0; i--) yield return elements[i]; } public IEnumerable<T> Subrange(int index, int n) { for (int i = 0; i < n; i++) yield return elements[index + i]; } } List<Item> items = GetItemList(); foreach (Item x in items) {…} foreach (Item x in items.Descending()) {…} foreach (Item x in Items.Subrange(10, 20)) {…} Demo Tipos Parciais public partial class Customer { public class Customer private int id; private string name; { private string address; private int id; private string name; private List<Orders> orders; private string address; } private List<Orders> orders; public partial class Customer public void SubmitOrder(Order order) { { orders.Add(order); public void SubmitOrder(Order order) { } orders.Add(order); } public bool HasOutstandingOrders() { return orders.Count > 0; public bool HasOutstandingOrders() { } return orders.Count } > 0; } } Classes Estáticas Pode conter apenas membros estáticos Não pode ser tipo de variável, parâmetro, … System.Console, System.Environment, … public static class Math { public static double Sin(double x) {…} public static double Cos(double x) {…} … } Acesso à Propriedades Diferentes níveis de acesso para Get/Set Típica configuração set {…} mais restrito que get {…} public class Customer { private string id; } public string CustomerId { get { return id; } internal set { id = value; } } Aliases Externos Assemblies com nomes de tipo idênticos Versões diferentes do mesmo assembly foo.dll bar.dll extern alias Foo; extern alias Bar; namespace Stuff namespace Stuff { { class Program public class public class Utils { Utils { { static void Main() { public staticFoo.Stuff.Utils.F(); void F() {…} public static void F() {…} } } Bar.Stuff.Utils.F(); } } } } C:\>csc /r:Foo=foo.dll /r:Bar=bar.dll test.cs Namespace Alias Qualifiers A::B procura por A como namespace alias global::X procura X no namespace global using IO = System.IO; class Program { static void Main() { IO::Stream s = new IO::File.OpenRead("foo.txt"); global::System.Console.WriteLine("Hello"); } } Controle de Warning #pragma warning using System; class Program { [Obsolete] static void Foo() {} static void Main() { #pragma warning disable 612 Foo(); #pragma warning restore 612 } } Threading Semaphore Resource counting for mutex’s // construct a semaphore with a count of 3 Semaphore sem = new Semaphore(3); private void UseResource { // Wait until a count is available… sem.WaitOne(); // the sem count is reduced by one // other code … // Release the count: sem.Release(); // the count is incremented by one Threading Named Events V1.0 and V1.1: Events can only signal the same process Whidbey: Named Events allow cross process communication Public Class EventWaitHandle Inherits WaitHandle Public Sub New EventWaitHandle(initialState As Boolean, type As EventType, name As String ) Longhorn and WinFX: Re-Invigorating the Virtuous Cycle • Applies .NET Framework goodness to core OS • Consistent, object oriented • Secure, reliable platform • Modern library and language designs • Enables new class of applications all built on managed code • Fuels ecosystems for the next decade of growth For More Information Applied Microsoft .NET Framework Programming (Richter) NET Framework Standard Library Annotated Reference, Vol. 1 (Abrams) http://blogs.msdn.com/brada Q&A © 2004 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.