Documente Academic
Documente Profesional
Documente Cultură
ISEL/DEETC 2010
Sumrio
a partir do C# 2.0
Exemplos
ISEL/DEETC 2010
Enumerveis e enumeradores
Quando um tipo passvel de ser enumerado, deve implementar a interface IEnumerable<T>, que contm o nico mtodo:
IEnumerator<T> GetEnumerator()
Mtodo no genrico IEnumerator GetEnumerator(), com implementao de forma explcita Mtodo genrico IEnumerator<T> GetEnumerator()
Acrescenta a interface IDisposable Mtodos Reset e MoveNext so de IEnumerator, embora o mtodo Reset no necessite de ser suportado Duas propriedades Current
ISEL/DEETC 2010
Utilizaes de IEnumerable/IEnumerator
A utilizao de enumeradores sobre tipos enumerveis pode ter dois tipos de implementaes/utilizaes:
Sequncias onde os elementos j esto calculados e armazenados numa estrutura de dados Sequncias onde os elementos so calculados apenas quando necessrios aquando da chamada do mtodo MoveNext
ISEL/DEETC 2010
Soluo 1 (eager)
Criar uma estrutura de dados s2 (ex. lista) que seja enumervel Percorrer s1, copiando para s2 todos os elementos de s1 que satisfazem p Retornar s2
public static IEnumerable<T> FilterToList<T> (IEnumerable<T> seq, Predicate<T> pred){ List<T> result = new List<T>(); foreach(T t in seq){ if(pred(t)) result.Add(t); } return result; }
ISEL/DEETC 2010
Soluo 2 (Lazy)
Retornar um objecto que implemente IEnumerable<T>, em que o enumerador associado possua as seguintes funcionalidades:
Contm um enumerador para s1 O mtodo MoveNext avana o enumerador sobre s1 enquanto o predicado falso A propriedade Current, retorna o elemento corrente de s1
ISEL/DEETC 2010
class Filter<T> : IEnumerable<T> { IEnumerable<T> enumerable; Predicate<T> pred; public Filter(IEnumerable<T> ie, Predicate<T> p) { enumerable = ie; pred = p; } public IEnumerator<T> GetEnumerator() { return new FilterEnumerator(enumerable.GetEnumerator(), pred); } }
ISEL/DEETC 2010
public FilterEnumerator(IEnumerator<T> ie, Predicate<T> p) { enumerator = ie; pred = p; } public void reset() { enumerator.reset(); }
public void Dispose() { enumerator.Dispose(); } public bool MoveNext() { bool b; while ((b = enumerator.MoveNext()) && pred(enumerator.Current) == false); return b; } public T Current { get { return enumerator.Current; } } }
ISEL/DEETC 2010
necessrio passar o predicado e o enumerador entre a fonte e a classe enumervel, e entre esta e a classe enumeradora Faltam ainda os mtodos das interfaces no genricas Lgica do mtodo MoveNext mais complexa quando comparada com a implementao no lazy public static IEnumerable<T> FilterToList<T> (IEnumerable<T> seq, Predicate<T> pred){ List<T> result = new List<T>(); foreach(T t in seq){ if(pred(t)) result.Add(t); } return result; }
ISEL/DEETC 2010
Corrotinas
MoveNext()
yield return a;
yield return b;
yield return c;
return false
ISEL/DEETC 2010
MoveNext()
Current = t
MoveNext()
public static IEnumerable<T> Filter<T>(IEnumerable<T> seq, Predicate<T> pred){ foreach (T t in seq) { if (pred(t)) yield return t; // result.Add(t); } }
ISEL/DEETC 2010
Iteradores
public static IEnumerable<T> Filter<T>(IEnumerable<T> ie, Predicate<T> pred) { foreach (T t in ie) { if (pred(t)) yield return t; } }
O mtodo Filter retorna uma classe gerada pelo compilador e que implementa IEnumerable<T> e IEnumerator<T>
Os seus mtodos, nomeadamente o MoveNext, reflectem a sequncia de aces definida no corpo da funo geradora O contexto da gerao capturado para ser usado no mtodo MoveNext
Sintaxe e semntica
yield return t sinaliza que o fio de execuo (do MoveNext) termina com true e Current = t yield break sinaliza que o fio de execuo (do MoveNext) termina com false (Current indeterminado)
ISEL/DEETC 2010
Variveis capturadas
ISEL/DEETC 2010
Contem campos com o contexto da gerao, que neste caso so os parmetros seq e pred Implementa simultaneamente IEnumerable<T> e IEnumerator<T>, com optimizao para o caso em que apenas criado um enumerador O mtodo MoveNext implementado atravs duma mquina de estados
Estado -2: ainda no foi obtido o enumerador Estado 0: enumerador no estado inicial Estado -1: enumerador no estado final Aspectos avanados da linguagem C#
ISEL/DEETC 2010
Campos para a implementao da mquina de estados Campos com o contexto capturado para o enumervel e para o enumerador private sealed class X : IEnumerable<T>, IEnumerator<T>{ // mquina de estados private int state; // estado do enumerador private T current; // elemento actual // campos do enumerador public IEnumerator<T> en; // enumerador fonte public Predicate<T> pred; // predicado public IEnumerable<T> seq;// enumervel fonte // campos do enumervel public Predicate<T> _pred; // predicado fonte public IEnumerable<T> _seq; // enumervel fonte public X(int _state){ state = _state;}
ISEL/DEETC 2010
Em caso positivo, aproveitada a mesma instncia Em caso negativo, criada uma nova instncia
else
d = new X(0); d.seq = this._seq; d.pred = this._pred; return d; }
ISEL/DEETC 2010
Projeco de sequncias
public static IEnumerable<U> Select<T,U>(IEnumerable<T> seq, Converter<T,U> selector) { foreach(T t in seq) yield return selector(t); }
ISEL/DEETC 2010
que retorna um enumervel com todos os elementos do enumervel col recebido, que satisfazem o predicado p. Tirando partido do mtodo Where, pretende-se implementar o mtodo inRange, frente, que retorna um enumervel com todos elementos de ts entre min e max
public static IEnumerable<T> InRange<T>( this IEnumerable<T> ts, T min, T max) where T : IComparable<T> { return Where(ts, ?); }
ISEL/DEETC 2010
Iteradores
class RangeComparer<T> where T : IComparable<T> { private T min, max; public RangeComparer(T mn, T mx) { min = mn; max = mx; } public bool IsInRange(T t) { return t.CompareTo(min) >= 0 && t.CompareTo(max) <= 0; } }
ISEL/DEETC 2010
Iteradores
public static IEnumerable<T> InRange2<T>( IEnumerable<T> ts, T min, T max) where T : IComparable<T> { return Where(ts, t => t.CompareTo(min) >= 0 && t.CompareTo(max) <= 0 ); } Com expresso lambda
ISEL/DEETC 2010
public static void ListFilesByExt(string path, string ext){ Predicate<FileInfo> predicate1 = null; X classe1 = new X(); classe1.ext = ext; // Acesso ao contexto predicate1 = new Predicate<FileInfo>(classe1.m); using (IEnumerator<FileInfo> enumerator1 = Global.Filter<FileInfo>( Global.GetDirectoryEnumerator( new DirectoryInfo(path)), A assinatura do mtodo annimo funo predicate1) tipo delegate, que inferido do contexto .GetEnumerator())
do
ISEL/DEETC 2010
Variveis capturadas
Variveis externas: variveis locais, parmetros valor e arrays de parmetros cujo scope inclua o mtodo annimo. Se o mtodo annimo estiver definido dentro dum mtodo instncia, ento this tambm uma varivel externa As variveis externas referidas pelo mtodo annimo dizem-se capturadas O compilador de C# cria uma classe com:
ISEL/DEETC 2010
Parmetros referncia (ref e out) no podem ser capturados uma vez que no possvel garantir a validade das referncias no momento da execuo do delegate
ISEL/DEETC 2010
C# 3.0: sumrio
Baseado em: Microsoft, C# Version 3.0 Specification September 2005, Setembro de 2005
ISEL/DEETC 2010
Expresses lambda
Tipificao implcita do parmetro, obtida atravs do contexto Corpo do mtodo uma expresso
ISEL/DEETC 2010
Mtodos de extenso
Mtodos estticos invocveis usando a sintaxe de mtodo de instncia Utilizao: simplificar a sintaxe de construo de pipelines Com mtodos estticos f3(f2(f1(source,p1),p2),p3) Com mtodos instncia source.f1(p1).f2(p2).f3(p3) Mtodos extenso (tm de estar presentes em classes estticas)
p1
p2
p3
ISEL/DEETC 2010
System.Query
O assembly System.Query define um conjunto de mtodos de extenso sobre IEnumerable<T> Exemplos
Restrio: Where Projeco: Select, SelectMany Ordenao: OrderBy, ThenBy Agrupamento: GroupBy Quantificadores: Any, All Partio: Take, Skip, TakeWhile, SkipWhile Conjuntos: Distinct, Union, Intersect, Except Elementos: First, FirstOrDefault, ElementAt Agregao: Count, Sum, Min, Max, Average Converso: ToArray, ToList, ToDictionary
Aspectos avanados da linguagem C# 29
ISEL/DEETC 2010
Exemplo
Apresentar todos os ficheiros com extenso .cs, ordenados pela data/hora do ltimo acesso de escrita
DirectoryInfo di = new DirectoryInfo(path); IEnumerable<FileInfo> fis = Global.GetDirectoryEnumerator(di) .Where(fi => fi.Extension == ".cs") .OrderBy(fi => fi.LastWriteTime);
Mtodo que retorna um enumervel com representantes de todos os ficheiros presentes na sub-rvore de directorias com raz em di
Salienta-se
Mtodos extenso ordem do Where e do OrderBy a ordem de execuo Expresses lambda simplicidade do predicado e da seleco de ordenao
Aspectos avanados da linguagem C# 30
ISEL/DEETC 2010
No tipificao dinmica, tipificao esttica com inferncia do tipo em tempo de compilao Utilizao
Tipos complexos Tipos annimos (ver slide seguinte) No pode ser usada no tipo de retorno ou no tipo dos parmetros
ISEL/DEETC 2010
Tipos annimos
Criao automtica de tipos para o armazenamento de tuplos
var point = new {X = 3, Y = 4}; Resulta na criao duma classe annima com as propriedades pblicas X e Y, do tipo int, inferidas do iniciador {X = 3, Y = 4}
Na mesma unidade de compilao, dois iniciadores iguais utilizam o mesmo tipo annimo Forma alternativa
int X = 3; int Y = 4 var point = new {X, Y}
Exemplo
Para cada ficheiro com extenso .cs apresentar o nome do ficheiro e o respectivo nmero de linhas
public static void ShowNumberOfLines(string path, string substring) { DirectoryInfo di = new DirectoryInfo(path); Mtodos auxiliares var res = GetDirectoryEnumerator(di) .Where(fi => fi.Extension == ".cs") .Select(fi => new { File = fi, Lines = CountLines(fi) });
foreach (var p in res) { Console.WriteLine("file = {0}; lines = {1}", p.File.FullName, p.Lines); }
ISEL/DEETC 2010
public static void ShowNumberOfLines2(string path, string substring) { DirectoryInfo di = new DirectoryInfo(path); var res = from fi in GetDirectoryEnumerator(di) where fi.Extension == ".cs" select new { File = fi, Lines = CountLines(fi) }; foreach (var p in res) { Console.WriteLine("file = {0}; lines = {1}", p.File.FullName, p.Lines); }
ISEL/DEETC 2010