SlideShare ist ein Scribd-Unternehmen logo
1 von 64
Downloaden Sie, um offline zu lesen
Editorial

EDITORIAL
  EQUIPA PROGRAMAR                                         Sempre em movimento…
                                    Coordenadores          Porque sabemos que parar é morrer, nesta edição da Revista
                                      António Silva        PROGRAMAR introduzimos várias alterações que achamos importantes
                                  Fernando Martins         para continuidade deste projecto. Das várias alterações introduzidas, a salta
                                                           imediatamente à vista, mesmo ao leitor que ainda está somente a ler a
                                              Editor       página do editorial, é a mudança de design . Em qualquer tipo de
                                       António Silva       publicação o design influencia o modo como vemos como lemos. Aqui
                                                           temos que agradecer a todos quantos ajudaram a adaptar este novo design,
                                        Design             mas especialmente ao Sérgio Alves por toda a parte da idealização e
                 Sérgio Alves (@scorpion_blood)            desenho do novo design.
                                                           Outra alteração, que todavia não será tão notada pelos leitores é a
                                      Redacção             alteração do software de paginação. Chegamos à conclusão que o Scribus
          André Lage, Augusto Manzano, Diogo               já evoluiu bastante desde a última vez que foi utilizado para paginar a
     Constantino, Fernando Martins, João Mares,            Revista PROGRAMAR e está à altura das nossas necessidades. Assim
     João Matos, Jorge Paulino, Paulo Morgado,             decidimos que não havia necessidade de continuarmos a utilizar um
      Pedro Aniceto, Ricardo Rodrigues, Ricardo            software pago e que trazia vários problemas de leitura a alguns utilizadores
                            Trindade, Sara Silva           (dos quais chegamos a receber comentários).
                                                           Também fizemos várias parcerias com algumas comunidades
                                      Contacto             portuguesas que estão de algum modo relacionadas com programação, de
     revistaprogramar@portugal-a-programar.info            modo a obter mais e melhores artigos para si. Todavia não estamos
                                                           fechados a mais parcerias, continuamos abertos a futuros contactos para o
                                         Website           nosso endereço de correio electrónico, que serão posteriormente analisados
                http://www.revista-programar.info          por toda a equipa.
                                                           Trazemos também até si, colunas de opinião e colunas direccionadas a
                                                ISSN       um tema específico. Assim poderá contar que surgirão artigos desse
                                          1 647-071 0      assunto com uma periodicidade específica na sua Revista favorita.
                                                           Por fim, achamos que estamos prontos para voltar a trazer a Revista
                                                           PROGRAMAR até si de 2 em 2 meses , e por isso a próxima edição deverá
  INDICE                                                   sair em Fevereiro ao invés de Março como estava programado.

4      Tema de Capa - LINQ                                 Tudo isto para si, que está ler. Esperámos que as alterações sejam bem
11     BYACC                                               recebidas por todos, mas também esperámos opiniões sobre todas estas
18     Introdução ao Entity Framework                      alterações, mesmo porque as novidades poderão não ficar por aqui,
23     Programação Funcional Perl (Parte I )               contámos ter mais novidades na próxima edição. Por isso não tenha medo
26     BackgroundWorkers em WPF                            de nos contactar para revistaprogramar@portugal-a-programar.org a dizer o
31     jQuery - O quê, como e porquê?                      que acha de todas estas alterações. Porque você é importante para nós,
35     Tutorial de Lua (Parte 6)                           quer as suas opiniões, quer o seu trabalho a divulgar o nosso projecto aos
41     E se amanhã a Apple dominar?                        seus amigos e colegas, e mais importante a sua preferência que nos
43     SQL em Oracle                                       permite crescer para lhe oferecer algo maior e melhor.
47     Aspectos low-level de 3D
54     Quando se é ! Produtivo                             A equipa da Revista PROGRAMAR
56     Client Object Model para Silverlight

A revista PROGRAMAR é um projecto voluntário, sem fins lucrativos. Todos os artigos são da responsabilidade dos autores, não podendo a revista ou a
comunidade ser responsabilizada por alguma imprecisão ou erro. Para qualquer dúvida ou esclarecimento poderá sempre contactar-nos.

                                                                         2
Noticias

                                                                                           NOTICIAS
 U p l o a d Li s b o a e U p l o a d Li s b o a                     Se m i n á ri o Po c ke tPT s o b re
 Pro 2 0 1 0                                                         te c n o l o gi a s Wi n d o ws Ph o n e
O Upload Lisboa é um evento que por si só nomeia a era              Encontram-se abertas as inscrições para o 6º Seminário
em que estamos. A era da nova comunicação, da troca de              PocketPT sobre tecnologias móveis Windows Phone. Este
informação no momento, de forma prática e natural, e da             ano o seminário será dedicado à nova plataforma móvel da
partilha de conhecimentos em rede. O Upload Lisboa                  Microsoft, e irá incluir várias sessões que irão dar a
pretende, mais uma vez, passar a esfera da rede interior e          conhecer as funcionalidades do mesmo.
global para a esfera da partilha conjunta, física.                  Será ainda uma excelente oportunidade para os
Este evento nasce da necessidade crescente de debate e              participantes testarem e verem em primeira mão os novos
partilha de conhecimentos sobre a web 2.0, numa altura em           equipamentos.
que as novas plataformas de comunicação e informação                Como tem vindo a acontecer nos anos anteriores a
assumem um lugar cada vez mais central na vida de                   inscrição este ano é gratuita e irá ter lugar no auditório da
pessoas e empresas. Hoje, mais que nunca, a partilha                Microsoft Portugal no TagusPark em Porto Salvo no
através das plataformas sociais na web ocupam um lugar              próximo dia 1 8 de Dezembro pelas 1 0h.
de destaque na influência na opinião pública e na formação          Mais informações e inscrições:
de critérios de análise ao que se passa no país e no                http://www.mtechseminar.com/201 0/index.htm
mundo.
São dois dias, 11 e 1 5 de Dezembro, que certamente não
irá perder!
Mais informações: http://uploadlisboa.com/



 SAPO C o d e B i ts 2 0 1 0                                         1 6 a R e u n i ã o Pre s e n c i a l d a
                                                                     C o m u n i d a d e N e tPo n to
De 11 a 1 3 de Novembro de 201 0 decorreu o Sapo                    No dia 11 /1 2/201 0 será realizada a 1 6ª reunião presencial
Codebits 201 0. A comunidade Portugal-a-Programar esteve            da comunidade NetPonto, em Lisboa. Nesta sessão,
presente, tendo alguns membros efectuado alguns                     poderá ver duas apresentações presenciais sobre Domain
projectos. Este ano, com oferta da comunidade, todos os             Driven Design e WP7 & XNA – Let’s play?
que participaram e solicitaram, tiveram direito a uma t-shirt       Para participar, basta efectuar a inscrição através do site
para usar durante o evento.                                         http://netponto-lisboa-dezembro-201 0.eventbrite.com/      A
Esta foi a foto de grupo de alguns dos elementos que                entrada é gratuita e são realizadas reuniões todos os
estiveram presentes (infelizmente não foi possível juntar           meses.
todos):                                                             Para mais informações, consulta de próximas sessões e
                                                                    inscrição: http://netponto.org/




                                                                3
TEMA DE CAPA

LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st,
Ta ke La stWh i l e , Ski p La st e S ki p La stWh i l e
Há algum tempo necessitei de obter os últimos              original uma vez e mais três vezes sobre os
itens de uma sequência que satisfaziam um                  itens que satisfazem o critério. Se a sequência
determinado critério e, olhando para os                    original for grande, isto pode consumir muita
operadores disponíveis na classe Enumerable,               memória e tempo.
apercebi-me de que tal operador não existia.
                                                           Existe ainda um problema adicional quando se
A única forma de obter o resultado pretendido              usa a variante que usa o índice de item na
era inverter a ordem dos itens na sequência,               sequência original na avaliação do critério de
obter os itens que satisfaziam o critério e inverter       selecção (>). Quando se inverte a ordem dos
os itens da sequência resultante.                          itens, os índices destes serão invertidos e o
                                                           predicado de avaliação do critério de selecção
Algo como isto:                                            terá de ter isso em consideração, o que poderá
                                                           não ser possível se não se souber o número de
 Sequence                                                  itens na sequência original.
   .Reverse()
       .TakeWhile(criteria)                                Tinha de haver uma solução melhor, e é por isso
             .Reverse();                                   que eu implementei os Operadores Take Last:

                                                           TakeLast<TSource>(IEnumerable<TSource>)
Parece simples, certo? Primeiro chamamos o
método Reverse para produzir uma nova                      Retorna o número especificado de elementos
sequência com os mesmos itens mas na ordem                 contínuos no fim da sequência.
inversa da sequência original, depois chamamos
                                                            int[] grades = { 59, 82, 70, 56, 92, 98, 85
o método TakeWhile para obter os primeiros
                                                            };
itens que satisfazem o critério e, finalmente,
chamamos novamente o método Reverse para
                                                                 var topThreeGrades = grades
recuperar a ordem original dos itens.
                                                                             .OrderBy(grade => grade)
                                                                             .TakeLast(3);
O problema desta aproximação é que o método
rev memoriza toda a sequência antes de iterar
                                                            Console.WriteLine("As     notas       mais   altas
sobre os seus itens na ordem inversa – e o
                                                            são:");
código acima usa-o duas vezes. Isto significa
iterar sobre todos os itens da sequência original
                                                            foreach (int grade in topThreeGrades)
e memoriza-los, iterar sobre os primeiros itens
                                                            {
que satisfazem o critério e memoriza-los e,
                                                                      Console.WriteLine(grade);
finalmente, iterar sobre estes itens para produzir
                                                            }
a sequência final.

Se estiveram a contar, chegaram à conclusão de
que se iterou sobre todos os itens da sequência

                                                       4
TEMA DE CAPA
                     LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e



 /*                                                                          string[] fruits =
 Este código produz o seguinte resultado:                                    { "maçã", "maracujá","banana", "manga",
 As notas mais altas são:                                                         "laranja", "mirtilo", "uva", "morango" };


 98                                                                          var query = fruits
 92                                                                                    .TakeLastWhile((fruit, index) =>
 85                                                                                    fruit.Length >= index);
 */
                                                                             foreach (string fruit in query)

TakeLastWhile<TSource>(IEnumerable<TSou                                      {

rce>, Func<TSource, Boolean>)                                                          Console.WriteLine(fruit);
                                                                             }

Retorna os elementos do fim da sequência para
os quais a condição especificada é verdadeira.                               /*
                                                                             Este código produz o seguinte resultado:
 string[] fruits =                                                           morango
 { "maçã", "maracujá","banana", "manga",                                     */
      "laranja", "mirtilo", "uva", "morango"
 };
                                                                           Tendo introduzido os operadores TakeLast, faz
 var query = fruits                                                        todo o sentido introduzido os seus duais: os
           .TakeLastWhile(fruit =>                                         operadores SkipLast:
           string.Compare("laranja",
           fruit, true) != 0);                                             SkipLast<TSource>(IEnumerable<TSource>)
 foreach (string fruit in query)                                           Retorna todos os elementos da sequência à
 {                                                                         excepção do número especificado de elementos
           Console.WriteLine(fruit);                                       contínuos no fim da sequência.
 }
                                                                             int[] grades =
 /*                                                                                    { 59, 82, 70, 56, 92, 98, 85 };
 Este código produz o seguinte resultado:                                    var lowerGrades = grades
 maracujá                                                                              .OrderBy(g => g)
 uva                                                                                   .SkipLast(3);
 morango
 */                                                                          Console.WriteLine("Todas as notas excepto as
                                                                             top 3:");


TakeLastWhile<TSource>(IEnumerable<TSou                                      foreach (int grade in lowerGrades)
rce>, Func<TSource, Int32, Boolean>)                                         {
                                                                                       Console.WriteLine(grade);
Retorna os elementos do fim da sequência para                                }
os quais a condição especificada é verdadeira.

                                                                     5
TEMA DE CAPA
LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e



  /*                                                                            SkipLastWhile<TSource>(IEnumerable<TSour
  Este código produz o seguinte resultado:                                      ce>, Func<TSource, Int32, Boolean>)
  As notas mais altas, excepto:
  56                                                                            Retorna todos os elementos da sequência à
  59                                                                            excepção dos elementos do fim da sequência
  70                                                                            para os quais a condição especificada é
  82                                                                            verdadeira.
  */
                                                                                   int[] amounts =
                                                                                   {
SkipLastWhile<TSource>(IEnumerable<TSour                                                     5000, 2500, 9000, 8000,
ce>, Func<TSource, Boolean>)                                                                 6500, 4000, 1500, 5500
                                                                                   };
Retorna todos os elementos da sequência à
excepção dos elementos do fim da sequência                                         var query = amounts
para os quais a condição especificada é                                                       .SkipWhile((amount, index) => amount >
verdadeira.                                                                        index * 1000);


  int[] grades =                                                                   foreach (int amount in query)
            { 59, 82, 70, 56, 92, 98, 85 };                                        {
  var lowerGrades = grades                                                                   Console.WriteLine(amount);
            .OrderBy(grade => grade)                                               }
            .SkipLastWhile(grade =>
            grade >= 80);                                                          /*
                                                                                   Este código produz o seguinte resultado:
  Console.WriteLine("Todas as notas menores que                                    5000
  80:");                                                                           2500
                                                                                   */
  foreach (int grade in lowerGrades)
  {
            Console.WriteLine(grade);
  }
                                                                                IMPLEMENTADO OS OPERADORES
                                                                                TAKELAST
  /*
                                                                                I mplementando O Operador TakeLast
  Este código produz o seguinte resultado:
  Todas as notas menores que 80:
                                                                                O operador TakeLast retorna o número
  56
                                                                                especificado de elementos contínuos do fim de
  59
                                                                                uma sequência e é implementado como o
  70
                                                                                método de extensão TakeLast.
  */

                                                                                Para implementar este operador, primeiro
                                                                                começamos por memorizar, pelo menos, o
                                                                                número requerido (count) de itens da sequência


                                                                           6
TEMA DE CAPA
                         LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e


fonte (source) num array que funciona como
                                                                                 for (; numOfItems > 0; idx = (idx + 1) %
uma memória intermédia (buffer) circular:
                                                                                 count, numOfItems--)
 var sourceEnumerator =                                                          {
 source.GetEnumerator();                                                                   yield return buffer[idx];
 var buffer = new TSource[count];                                                }
 var numOfItems = 0;
 int idx;
                                                                               Há duas optimizações que ainda podemos fazer.
 for (idx = 0; (idx < count) &&
 sourceEnumerator.MoveNext(); idx++,
                                                                               A primeira é óbvia, se o número de itens
 numOfItems++)
                                                                               requerido for 0 (zero), retornamos uma
 {
                                                                               sequência vazia:
 buffer[idx] = sourceEnumerator.Current;                                         if (count <= 0)
                                                                                 {
Se o número de itens memorizados                                                     return
(numOfItems) for inferior ao número requerido                                          System.Linq.Enumerable.Empty<TSource>();
(count), produzimos os itens memorizados:                                        }


 if (numOfItems < count)
                                                                               A segunda é se a sequência fonte (source)
 {
                                                                               implementar a interface IList<T>. Os objectos
          for (idx = 0; idx < numOfItems; idx++)
                                                                               que implementam esta interface têm uma
           {
                                                                               propriedade Count e acesso indexado aos seus
                    yield return buffer[idx];
                                                                               itens que nos permite optimizar a produção da
           }
                                                                               sequência final.
           yield break;
     }
                                                                               A produção da sequência final passa por
                                                                               produzir o número de itens requeridos do fim da
Em seguida, iteramos pelos restantes itens e                                   lista (ou todos se a lista contiver menos que os
vamos os armazenando, de forma circular, na                                    itens requeridos):
memória intermédia:
                                                                                 int listCount = list.Count;
 for     (idx   =   0;    sourceEnumerator.MoveNext();                           for (int idx = listCount - ((count <
 idx = (idx + 1) % count)                                                        listCount) ? count : listCount); idx <
 {                                                                               listCount; idx++)
                                           buffer[idx]           =               {
 sourceEnumerator.Current;                                                                 yield return list[idx];
 }                                                                               }


                                                                               Implementando os Operadores
E finalmente, iteramos sobre os itens                                          TakeLastWhile
memorizados para produzir a sequência final:
                                                                               O operador TakeLastWhile retorna os últimos


                                                                         7
TEMA DE CAPA
LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e


elementos contíguos que satisfazem o critério
                                                                                               buffer.Add(item);
especificado e é implementado como os
                                                                                        }
métodos de extensão TakeLastWhile.
                                                                                        else
Para implementar este operador, primeiro
                                                                                        {
começamos com uma memória intermédia
                                                                                               buffer.Clear();
(buffer) vazia e, para cada item que satisfaça o
                                                                                        }
critério implementado pelo predicado (predicate),
                                                                                   }
memorizamos esse item. Sempre que ocorrer
um item que não satisfaça o critério de selecção,
                                                                                   foreach (var item in buffer)
a memória intermédia é limpa:
                                                                                   {
  var buffer = new List<TSource>();                                                     yield return item;
  foreach (var item in source)                                                     }
  {
       if (predicate(item))
       {
                                                                                IMPLEMENTANDO OS OPERADORES
              buffer.Add(item);
                                                                                SKIPLAST
       }
       else
                                                                                Implementando o Operador SkipLast
       {
              buffer.Clear();
                                                                                O operador SkipLast retorna o número
       }
                                                                                especificado de elementos contínuos do fim de
  }
                                                                                uma sequência e é implementado como o
                                                                                método de extensão SkipLast.
Depois de percorrer toda a sequência fonte                                      Para implementar este operador, começamos
(source), produzimos todos os itens, se                                         por memorizar, pelo menos, o número requerido
existirem, da memória intermédia:                                               (count) de itens da sequência fonte (source) num
                                                                                array que funciona como uma memória
  foreach (var item in buffer)                                                  intermédia (buffer) circular:
  {
       yield return item;                                                          var sourceEnumerator =
  }                                                                                source.GetEnumerator();
                                                                                   var buffer = new TSource[count];
A diferença para o método que tem em conta o                                       int idx;
índice do item no predicado (predicate) de
selecção é apenas na invocação deste:                                              for (idx = 0; (idx < count) &&
                                                                                   sourceEnumerator.MoveNext(); idx++)
  var buffer = new List<TSource>();                                                {
  var idx = 0;                                                                          buffer[idx] = sourceEnumerator.Current;
                                                                                   }
  foreach (var item in source)
  {
                                                                                Em seguida, iteramos pelos restantes itens da
       if (predicate(item, idx++))
                                                                                sequência fonte (source) memorizando
       {


                                                                           8
TEMA DE CAPA
                   LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e


circularmente cada item e produzindo o item
                                                                           var list = source as IList<TSource>;
armazenado anteriormente na mesma posição:
                                                                           if (list != null)

 idx = 0;                                                                  {
                                                                                 if (count >= list.Count)

 while (sourceEnumerator.MoveNext())                                             {

 {                                                                                   return

     var item = buffer[idx];                                                      System.Linq.Enumerable.Empty<TSource>();

     buffer[idx] = sourceEnumerator.Current;                                     }

     idx = (idx + 1) % count;                                                    // ...
                                                                           }

     yield return item;
 }
                                                                         Se o número de itens da sequência fonte
                                                                         (source) for superior ao número de itens a
Se o número de itens a excluir for igual ou                              excluir, produzir a sequência final consiste em
superior ao número de itens existentes na                                produzir todos os itens da sequência fonte
sequência fonte (source), o método                                       (source) excepto os últimos count itens:
sourceEnumerator.MoveNext() retornará false na
primeira iteração do ciclo while e será produzida                          int returnCount = list.Count - count;
uma sequência vazia.
                                                                           for (int idx = 0; idx < returnCount; idx++)
Tal como acontecia com o operador TakeLast,                                {
podem-se fazer algumas optimizações.                                             yield return list[idx];
                                                                           }
A primeira é óbvia, se o número de itens
requeridos for 0 (zero) ou inferior, retornamos                          Implementando os Operadores
uma sequência equivalente à fonte (source):                              SkipLastWhile
 if (count <= 0)                                                         O operador SkipLastWhile retorna os últimos
 {                                                                       elementos contíguos que satisfazem o critério
     return source.Select(i => i);                                       especificado e é implementado como os
 }                                                                       métodos de extensão SkipLastWhile.

                                                                         Para implementar este operador, primeiro
A segunda é se a sequência fonte (source)                                começamos com uma memória intermédia
implementar a interface IList<T>. Os objectos                            (buffer) vazia e, para cada item que satisfaça o
que implementam esta interface têm uma                                   critério implementado pelo predicado (predicate),
propriedade Count e acesso indexado aos seus                             memorizamos esse item.
itens que nos permite optimizar a produção da
sequência final.                                                         Sempre que ocorrer um item que não satisfaça o
                                                                         critério de selecção, a memória intermédia é
Se o número de itens a excluir for igual ou                              limpa e o item que não satisfaz o critério é
superior ao número de itens da sequência fonte                           produzido:
(source), retornamos uma sequência vazia:

                                                                   9
TEMA DE CAPA
LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e



  var buffer = new List<TSource>();                                                     else
  foreach (var item in source)                                                          {
  {                                                                                            if (buffer.Count > 0)
       if (predicate(item))                                                                    {
       {                                                                                        foreach (var bufferedItem in buffer)
              buffer.Add(item);                                                                     {
       }                                                                                                  yield return bufferedItem;
       else                                                                                         }
       {                                                                                            buffer.Clear();
              if (buffer.Count > 0)                                                            }
              {                                                                                yield return item;
               foreach (var bufferedItem in buffer)                                     }
                   {                                                               }
                       yield return bufferedItem;
                   }
                   buffer.Clear();
                                                                                Conclusão
              }
                                                                                Como podem ver, implementar este tipo de
              yield return item;
                                                                                operadores é muito fácil, pelo que, não se deve
       }
                                                                                evitar a sua implementação sempre que se
  }
                                                                                justifique. Implementar um específico para a
                                                                                nossa aplicação pode significar uma melhor
A diferença para o método que tem em conta o                                    legibilidade do código e até um aumento de
índice do item no predicado (predicate) de                                      performance.
selecção é apenas na invocação deste:                                           Podem encontrar a implementação completa
                                                                                destes operadores (e outros) no meu projecto de
  var buffer = new List<TSource>();
                                                                                utilitários e operadores para LINQ no CodePlex:
  var idx = 0;
                                                                                PauloMorgado.Linq.
  foreach (var item in source)
                                                                                Recursos
  {
                                                                                O meu website: http://PauloMorgado.NET/
       if (predicate(item, idx++))
                                                                                Livro “LINQ Com C#”
       {
                                                                                PauloMorgado.Linq
              buffer.Add(item);
                                                                                Classe Enumerable
       }
                                                                                Métodos de extensão

 AUTOR

                        Escrito por Paulo Morgado
                        É licenciado em Engenharia Electrónica e Telecomunicações (Sistemas Digitais) pelo Instituto Superior de
                        Engenharia de Lisboa e Licenciado em Engenharia Informática pela Faculdade de Ciências e Tecnologia
                        da Universidade Nova de Lisboa. Pelo seu contributo para a comunidade de desenvolvimento em .NET
                        em língua Portuguesa, a Microsoft premeia-o com o prémio MVP (C#) desde 2003. É ainda co-autor do
                        livro “LINQ Com C#” da FCA.



                                                                           10
A PROGRAMAR

BYAC C
No artigo anterior adquirimos algumas noções              eles seguem a gramática que ele define. Se o
sobre flex e vimos como implementar um                    objectivo do parser for só verificar que um certo
scanner simples. Relembrando, o flex é um                 ficheiro, por exemplo um ficheiro xml, segue a
gerador de analisadores lexicais ou scanners, e           especificação da linguagem, podemos não ter
o byacc é um gerador de parsers. Usados em                interesse nenhum em saber o valor de qualquer
conjunto permitem escrever aplicações bastante            token. A nossa calculadora no entanto, precisa
sofisticadas, mas no nosso artigo limitamo-nos a          de produzir resultados, portanto necessita de
considerar uma calculadora simples, servindo              saber o valor de cada token NUMBER que
como exemplo introdutório. Agora que temos o              recebe. O parser define os tokens e o tipo de
scanner para a nossa calculadora escrito                  valores que lhes podem estar associados na
podemos começar a considerar o parser.                    zona das definições, sempre que precisa de um
                                                          token novo ele chama o scanner com o resto do
Um ficheiro byacc tem a mesma estrutura que o             input que falta analisar. Vejamos a definição dos
flex, já que o analisador lexical em que o flex se        tokens para a nossa calculadora:
baseia, o lex, copiou a sua estrutura do yacc, o
gerador de parsers em que o byacc se baseia.               %union {
Como tal o nosso ficheiro byacc vai ser algo                    double d;
deste género:                                              };

 definições                                                %token<d> NUMBER
                                                           %token NL
 %%

                                                           %left '+' '-'
 gramática                                                 %left '*' '/'
                                                           %right '^'
 %%                                                        %nonassoc UMINUS

 int main()
 {                                                         %%
        yyparse();
 }                                                         ...


                                                           %%
Comecemos por considerar como é que o parser
e o scanner funcionam em conjunto. Um parser               int main()
recebe tokens e verifica se esses tokens estão a           {
seguir uma gramática. O que nós estávamos a                          yyparse();
retornar no scanner, o NUMBER e o NL são                   }
esses tokens. Os tokens podem ter um valor
associado ou não. O que o parser faz é ver se

                                                     11
A PROGRAMAR
BYAC C


A primeira coisa que encontramos é uma
%union, seguida da declaração de dois tokens,                    %%
NUMBER e NL. A %union serve para indicar                         expr_list      : expr NL                   { std::cout
tipos que queiramos associar a tokens e                          << $1 << std::endl; }
eventualmente a elementos da gramática. Ao                                           |   expr_list   expr     NL        {
escrevermos %token<d> NUMBER estamos a                           std::cout << $2 << std::endl; }
indicar que para além de NUMBER ser um                                               ;
token, tem um valor associado do tipo d, neste
caso double. Isto vai ser importante quando                      expr     : NUMBER           { $$ = $1; }
passarmos para a gramática e é por esta razão                              | '-' expr %prec UMINUS              { $$ =
que no scanner passávamos o número que                           -$2; }
tínhamos lido ao yylval.d antes de retornarmos o                           | expr '+' expr                         { $$ =
token. A informação da union e dos tokens que                    $1+$3; }
escrevermos nesta secção vai servir para o                                 | expr '-' expr                  { $$ = $1-
byacc gerar o header ao qual o nosso scanner                     $3; }
fez #include e que permite ao scanner e ao                                 | expr '*' expr                         { $$ =
parser comunicarem entre si. O '+', '-', '*', '/', '^' e         $1*$3; }
UMINUS também são tokens mas aqui para                                     | expr '/' expr                         { $$ =
além de indicarmos que são tokens estamos a                      $1/$3; }
indicar a associatividade dos operadores, um                               | expr '^' expr                         { $$ =
conceito que o leitor deverá conhecer, mas que                   pow($1, $3); }
abordaremos com maior profundidade na                                      | '(' expr ')'                    { $$ = $2;
gramática.                                                       }
                                                                           ;
 %{
 #include <iostream>
 #include <cmath>
                                                                 %%
 %}

                                                                 int main()
                                                                 {
 %union {
                                                                           yyparse();
      double d;
                                                                 }
 };

                                                                Esta versão do parser introduz a gramática, mas
 %token<d> NUMBER                                               comecemos por observar as diferenças na
 %token NL                                                      secção das definições. Podemos ver primeiro
                                                                que a introdução de código C/C++ se processa
 %left '+' '-'                                                  da mesma forma que no scanner. Em seguida
 %left '*' '/'                                                  temos a instrução, %type<d> expr, expr não é
 %right '^'                                                     um token, é outro símbolo da gramática mas
 %nonassoc UMINUS                                               ainda assim tem um tipo, portanto temos que o
                                                                indicar.
 %type<d> expr

                                                                Uma gramática, tal como a gramática da língua

                                                           12
A PROGRAMAR
                                                                                                         BYAC C


portuguesa, serve para nos indicar a estrutura           faz sentido criar várias produções para um stmt,
da linguagem, quais as composições de                    já que um stmt pode ser várias coisas. Neste
elementos que são válidas ou não de acordo               caso, um while, um if, um bloco, e continuando
com a linguagem. É fácil de ver como isto é útil         teríamos um for, um switch, um do while, etc.
para um compilador. A nossa calculadora tem              Sendo usual a existência de várias produções
uma gramática muito simples, mas ainda assim             com a mesma cabeça, o byacc permite usar a
tem-la, portanto temos que compreender alguns            seguinte sintaxe, com significado equivalente,
princípios sobre gramáticas. As gramáticas são           para aumentar a legibilidade:
um conjunto de regras, às quais chamamos
                                                          stmt     : WHILE expression stmt
produções, constituídas por uma cabeça e um
                                                                   | IF expression stmt
corpo. Por exemplo,
                                                                   | IF expression stmt ELSE stmt
                                                                   | block
 stmt : WHILE expression stmt;
                                                                 ...
                                                                   ;
é uma produção, com cabeça stmt e corpo
WHILE expression stmt. A cabeça indica-nos               Se quiséssemos escrever um parser para uma
uma construção da gramática e o corpo como               linguagem de programação, tínhamos de ter
ela é composta. Os elementos duma gramática              uma forma de relacionar as várias regras, por
dividem-se em símbolos terminais e não                   outras palavras uma gramática necessita de
terminais, sendo os terminais, para efeitos deste        uma estrutura. A forma de criar essa estrutura é
artigo, os tokens que o scanner envia e os não-          criando um símbolo não terminal inicial ao qual
terminais as cabeças de produções, ou seja               todos os outros estão subordinados. Pode ajudar
símbolos que podem ser produzidos através                pensar na estrutura da gramática como uma
doutros símbolos.                                        árvore na qual o símbolo não terminal inicial é a
                                                         raiz, os outros não terminais são nós e os
Por clareza, usamos maiúsculas para                      terminais são as folhas.
representar terminais e minúsculas para não
terminais, logo, no exemplo acima, stmt e                 %%
expression são símbolos não terminais enquanto
que o WHILE é terminal. Um símbolo terminal               program : list
não pode ser obtido através da junção de outros                         ;
símbolos, portanto só pode aparecer em corpos
de produções. Um não terminal por outro lado              list         : statement
pode ser derivado de terminais e outros não                             | list statement
terminais, logo pode aparecer tanto na cabeça                           ;
como no corpo duma produção. Um símbolo não
terminal pode, e habitualmente, tem várias                statement : declaration
definições. Pegando no exemplo anterior e                                   | function
expandindo, obtemos,                                                        ;

 stmt : WHILE expression stmt;
                                                          declaration : type identifier
 stmt : IF expression stmt;
                                                                                |    type   identifier    '='
 stmt : IF expression stmt ELSE stmt;
                                                          expression
 stmt : block;
                                                                                ;
 ...

                                                    13
A PROGRAMAR
BYAC C



                                                          s : x
                                                            | y
 type : INT
                                                            ;
         | DOUBLE
                                                          x : A B C ;
         | CHAR
                                                          y : A B C ;
         ;

                                                         Este caso é óbvio, temos duas produções
 function : type identifier '(' arg_list ')'             diferentes com o mesmo corpo, o parser não
 block                                                   sabe qual deve usar quando recebe os três
                 ;                                       tokens. O mesmo se passa nos casos seguintes.
 block : '{' stmt_list '}'                                s : x
             ;                                              | y
                                                            ;
 stmt_list : stmt                                         x : A B C ;
                     | stmt_list stmt                     y : A z C ;
                     ;                                    z : B ;
 ...
 %%                                                       s : x
                                                            | y
Acima temos um esqueleto de uma linguagem                   ;
muito simplificada, ainda com vários não                  x : A B C ;
terminais sem produções associadas, mas basta             y : z C ;
para termos uma noção da estrutura duma                   z : A B ;
gramática. Qualquer que seja o programa escrito
para esta linguagem, se ele estiver                      O byacc só tem um token de lookahead, ou seja,
sintacticamente correcto deve ser possível partir        no caso abaixo ele não consegue decidir se o
de program e derivar todos os elementos que o            que recebeu foi o x ou o y porque no momento
compõem. Neste caso program é o símbolo                  de escolher a produção ele só sabe que o se
inicial da gramática, e indicamos isso ao byacc          segue é o token C. Como existem dois casos
colocando-o como a primeira produção do                  com o token C, ele não sabe o que fazer. Isto
ficheiro.                                                não é um problema com a gramática, é uma
Já vimos nos exemplos anteriores que as                  limitação do byacc.
produções podem ser recursivas, o corpo duma
produção pode conter o mesmo não terminal
                                                          s : x C D
que é a cabeça. A recursividade é necessária e
                                                            | y C F
algo que o byacc processa muito eficientemente,
                                                            ;
mas usada sem cuidado é uma das coisas que
                                                          x : A B;
introduz conflictos na gramática. Um conflicto
                                                          y : A B;
surge quando o parser não sabe que regra usar
para uma determinada sequência de tokens. Um             O mesmo não ocorre no caso seguinte. Nesta
exemplo segue-se:                                        situação ele consegue saber que produção usar
                                                         vendo se o lookahead é D ou F.


                                                    14
A PROGRAMAR
                                                                                                     BYAC C



 s : x D                                                    %nonassoc IFX
   | y F                                                    %token ELSE
   ;
 x : A B;                                                   ...
 y : A B;
                                                            %%
A existência de conflictos na gramática não
impede o parser de ser gerado, já que o byacc
                                                            ...
tem comportamentos default quando não sabe
que produção usar, mas claro que o
                                                            stmt : IF expression stmt   %prec IFX
comportamento default pode não ser o que o
                                                                  | IF expression stmt ELSE stmt
programador tinha em mente quando escreveu a
                                                                  ;
gramática portanto convém eliminar os conflictos
antes de gerar o parser.
                                                            ...
                                                            %%
Os conflictos são introduzidos na escrita da
gramática e podem sempre ser eliminados
reescrevendo-a, mas por vezes é preferível                 Introduzimos o token IFX - o token ELSE já tem
eliminá-los usando precedências. Tomemos o                 de estar definido, tal como o IF se o estamos a
seguinte exemplo clássico, o “dangling else”:              usar na gramática - que não é retornado pelo
                                                           scanner. O IFX só existe dentro do parser e
 stmt : IF expression stmt                                 serve apenas para indicar o nível de
         | IF expression stmt ELSE stmt                    precedência de uma produção. Indicamos ao
         ;                                                 byacc o nível de precedência dos tokens pela
                                                           ordem em que os declaramos, tendo os últimos
Para o seguinte input:                                     maior precedência que os primeiros. A
                                                           precedência de um token determina a
 if(a)                                                     precedência da produção em que ele se
       if(b) c = a + b; else c = a;                        encontra, numa situação em que duas
                                                           produções são viáveis como no exemplo anterior
O problema que nos surge é que o parser não                a produção com maior precedência é usada. Se
sabe se o que ele tem é um IF expression stmt              quisermos modificar a precedência de uma
com expression igual a (a) e o stmt igual a if(b) c        produção sem afectar a precedência de nenhum
= a + b; else c = a; ou se em vez disso tem um             dos seus tokens, podemos, como mencionado
IF expression stmt ELSE stmt com expression                previamente, criar um token “falso” como o IFX e
também igual a (a), o primeiro stmt igual a if(b) c        escrever %prec IFX no fim da produção para o
= a + b; e o segundo stmt igual a c = a;. O que            conseguir. Usando o token IFX no primeiro IF
queremos que o parser faça? Associe o else ao              estamos a dizer que aquele tipo de if tem menos
primeiro if ou ao segundo? O comportamento                 precedência que o segundo IF,já que o token IFX
que esperamos é que associe ao segundo,                    é declarado antes do token ELSE, portanto
portanto para o conseguir vamos usar                       quando existem as duas hipóteses o parser
precedências.                                              escolhe sempre a segunda, o que é o
                                                           comportamento que desejávamos.


                                                      15
A PROGRAMAR
BYAC C



 expr : expr '*' expr                                           | expr '^' expr
         | NUMBER                                               | '(' expr ')'
         ;                                                      ;

Neste caso para o input NUMBER * NUMBER *                Dizemos que os operadores binários '+' e '-' são
NUMBER por exemplo, o parser não sabe se há-             associativos à esquerda e têm a mesma
de fazer (NUMBER * NUMBER) * NUMBER ou                   precedência. Os operadores '*' e '/' funcionam de
NUMBER * (NUMBER * NUMBER). Para                         forma idêntica mas têm maior precedência. O
resolver este problema precisamos de indicar a           operador de potência '^' é associativo à direita e
associatividade do operador binário '*' ao byacc.        tem a maior precedência de todos os operadores
Um operador com associatividade à esquerda               binários. O UMINUS indica que uma expressão
para o input NUMBER * NUMBER * NUMBER *                  negada tem a maior precedência e que não se
NUMBER faz ((NUMBER * NUMBER) *                          pode negar uma negação. Os parênteses forçam
NUMBER) * NUMBER, um operador com                        a avaliação de qualquer que seja a expressão
associatividade à direita faz NUMBER *                   que estiver dentro deles, contornando as
(NUMBER * (NUMBER * NUMBER)) para o                      precedências caso seja necessário. Para o input,
mesmo input. A forma de indicar a                        -1 ^2 + 5 + 3 - 2 * 3 ^ 4 ^ 5 / -6 / 2 - 5 a nossa
associatividade de um token ao byacc é                   gramática vai fazer (((((-1 )^2) + 5) + 3) - (((2 * (3
escrever %left ou %right em vez de %token                ^ (4 ^ 5))) / (-6)) / 2)) - 5 como seria de esperar.
quando o declaramos. Para declarar um
operador unário não associativo (ou seja um              Podemos associar acções a cada produção,
operador que não se pode encadear)                       para serem executadas quando o parser acaba
escrevemos %nonassoc em vez de %token.                   de processar o corpo de uma produção e o
                                                         substitui pela cabeça. As acções indicam-se da
Entendendo associatividade e precedências                mesma forma que no scanner, e é possível usar
podemos começar a compreender a gramática                elementos da produção dentro delas desde que
da nossa calculadora.                                    eles tenham valores associados. Para indicar o
                                                         valor da cabeça usamos $$, para os membros
 %token NUMBER
                                                         do corpo usamos $1 , $2, … $n de acordo com a
                                                         ordem em que eles aparecem. Um não terminal
 %left '+' '-'
                                                         tem por default associado um int. Se quisermos
 %left '*' '/'
                                                         associar um tipo diferente declaramos
 %right '^'
                                                         %type<tipo-do-valor-associado>            nome-do-
 %nonassoc UMINUS
                                                         símbolo-não-terminal na primeira secção do
                                                         ficheiro. Vejamos então o ficheiro inteiro:
 %%

                                                          %%
 expr : NUMBER
                                                          %{
         | '-' expr %prec UMINUS
                                                          #include <iostream>
         | expr '+' expr
                                                          #include <cmath>
         | expr '-' expr
                                                          %}
         | expr '*' expr
         | expr '/' expr


                                                    16
A PROGRAMAR
                                                                                                                    BYAC C


                                                                                        tipos              associados,
 %union {
                                                                                        associatividade              e
      double d;
                                                                                        precedência. Concluímos a
 };
                                                                                        primeira secção com a
                                                                                        declaração que o símbolo não
 %token<d> NUMBER
                                                                                        terminal expr tem um valor
 %token NL
                                                                                        associado do tipo double. Isto
 %left '+' '-'
                                                                                        é essencial porque as nossas
 %left '*' '/'
                                                                                        operações não estão a
 %right '^'
                                                                                        receber tokens NUMBER
 %nonassoc UMINUS
                                                                                        como argumentos mas sim
 %type<d> expr
                                                                                        não terminais expr. O símbolo
                                                                                        inicial da nossa gramática é
 %%
                                                                                        expr_list e está definido como
 expr_list        : expr NL              { std::cout << $1 << std::endl; }
                                                                                        uma sequência de um ou mais
                    | expr_list expr NL     { std::cout << $2 << std::endl; }
                                                                                        não terminais expr, separados
                    ;
                                                                                        por mudanças de linha.
                                                                                        Associamos a cada produção
 expr : NUMBER                           { $$ = $1; }
                                                                                        de expr_list a acção da
         | '-' expr %prec UMINUS         { $$ = -$2; }
                                                                                        impressão do valor de expr.
         | expr '+' expr                 { $$ = $1+$3; }
                                                                                        As produções com cabeça
         | expr '-' expr                 { $$ = $1-$3; }
                                                                                        expr tem associadas as
         | expr '*' expr                 { $$ = $1*$3; }
                                                                                        acções que realizam os
         | expr '/' expr                 { $$ = $1/$3; }
                                                                                        cálculos,    guardando      os
         | expr '^' expr                 { $$ = pow($1, $3); }
                                                                                        valores na cabeça. Na terceira
         | '(' expr ')'                  { $$ = $2; }
                                                                                        secção temos um main que
         ;
                                                                                        chama o yyparse().
 %%
 int main()
                                                                                     Neste momento temos um
 {
                                                                                     parser e um scanner para a
             yyparse();
                                                                                     nossa calculadora, no próximo
 }
                                                                                     artigo veremos como ligá-los e
O ficheiro começa com os #includes de C++ que                                        como modificar o scanner e o
precisamos, seguidos da %union com o único                         parser em conjunto de forma a adicionar mais
tipo que a nossa calculadora necessita, um                         funcionalidades à calculadora.
double. Lemos a declaração dos tokens, com os
 AUTOR

                     Escrito por João Mares
                     Estando actualmente no terceiro ano de LEIC no IST, interssa-se preferencialmente por arquitectura de
                     computadores e computação gráfica.




                                                              17
VISUAL (NOT) BASIC

I n tro d u ç ã o a o E n ti ty Fra m e wo rk
O ADO.NET Entity Framework permite criar                 tenham como nome “Jorge” e que tenham como
aplicações em que o acesso a dados é feito com           morada a “Moita”.
base em um modelo conceitual e não utilizando
comandos directos à base de dados. Isto                  Imaginemos que o programador ou o DBA
permite que o programador se abstraia                    (database administrator) altera o campo “nome”
totalmente da base de dados (criação de                  para “nomecompleto”, pois quer que se registe o
ligações de acesso, comandos, parâmetros, etc.)          nome completo do utilizador e, desta forma, o
e utilize apenas objectos durante o                      nome do campo fica mais coerente. Se
desenvolvimento.                                         aplicação for compilada não é detectado
                                                         qualquer problema e só no momento de
A versão 4.0 do Entity Framework (actual), que           execução irá ocorrer um erro. Situações como
está disponível na .NET Framework 4.0, tem um            estas são muito frequentes e podem
conjunto de novas funcionalidades e melhorias,           representam vários erros na aplicação.
como é o caso de suporte a POCO - Plain Old
CLR Objects (permite criar classes que não               Este é apenas um exemplo de como se pode
herdam, nem implementam nenhuma outra                    beneficiar, e muito, da utilização do Entity
classes ou interface), abordagem Model-First             Framework, mas existem muito mais vantagens
(permite criar primeiro o modelo conceptual e,           como a utilização de LINQ to Entities,
com base nele, criar a base de dados), suporte           intellisense no momento em que se está a
para o uso de funções em LINQ-to-Entities,               escrever o código, código mais fácil de manter e
Complex Types (criação de tipos de dados                 actualizar, etc, etc.
complexos), Deferred Loading ou Lazy Loading
(capacidade de carregar as propriedades de               Neste artigo, que será uma breve introdução ao
associação das entidades no momento em são               Entity Framework, irá apenas mostrar como
chamadas, se forem chamadas), etc. Não é                 construir um modelo relacional de uma base de
especifica apenas para o SQL Server, pois                dados SQL, uma abordagem database-first, e
existem providers que permitem usar outras               como executar algumas operações CRUD.
bases de dados, como Oracle, MySql,
PostgreSQL, DB2, SQL Anywhere, Ingres,                   CRIAÇÃO DO          MODELO       RELACIONAL
Progress, Firebird, Synergy, etc.                        (database-first)
Existem várias vantagens na utilização de um             Para criação de um modelo relacional iremos
ORM (Object-relational mapping), que tornam a            usar a seguinte base de dados SQL:
sua adopção quase inevitável, mas vejamos o
seguinte exemplo:

“SELECT * FROM utilizadores WHERE nome =
‘Jorge’ AND morada = ‘Moita’”

Este exemplo irá listar todos os utilizadores que

                                                    18
VISUAL (NOT) BASIC
                                                                         I n tro d u ç ã o a o E n ti ty Fra m e wo rk


                                                        Para o nome da ligação, e para este exemplo,
Como é possível ver nesta imagem, existem               utilize “vendasEntities“.
apenas 3 tabelas, com as respectivas chaves
primárias/estrangeiras: produtos, clientes e uma        A última opção deste Wizard é onde são
terceira tabela onde se registam os movimentos.         seleccionados os objectos a utilizar no modelo.
                                                        Neste exemplo são escolhidas as três tabelas já
O primeiro passo é adicionar um novo item ao            referidas.
projecto (menu Project – Add New Item), e
seleccionar no grupo de templates “Data” o item
“ADO.NET Entity Data Model”. Isto irá iniciar um
Wizard que permitirá criar o modelo final.




De seguida seleccionar “Generate           from
database” e carregar em “Next”.
                                                        Após este processo está criado o ficheiro EDMX,
A próxima opção permite fazer a ligação à base          que não é mais do que um conjunto de classes e
de dados, escolhendo uma já existente ou                métodos que nos permitirá aceder à base de
criando uma nova ligação.                               dados de uma forma simples, como iremos ver
                                                        de seguida.
                                                        OPERAÇÕES CRUD




                                                        As operações CRUD (acrónimo de Create,
                                                        Read, Update e Delete em Inglês) são quatro
                                                        operações básicas e fundamentais para a
                                                        manipulação de bases de dados. São por isso

                                                   19
VISUAL (NOT) BASIC
I n tro d u ç ã o a o E n ti ty Fra m e wo rk


bastante importantes e requerem, sem a
utilização de um ORM como o Entity Framework,
                                                            context.clientes.AddObject(cliente)
algum trabalho que é normalmente complexo.
                                                            context.SaveChanges()

Com o Entity Framework este trabalho está
                                                            ' Podemos verificar logo o número
bastante simplificado para o programador,
                                                            '   (ID) do registo inserido
necessitando apenas de algumas linhas de
                                                           Debug.WriteLine("Número de registo: " &
código, com recurso a IntelliSense, para as
                                                                            cliente.id.ToString())
executar.
                                                        End Using
O funcionamento para todas as operações é
semelhante: é criada uma nova instância da
nossa entidade (neste exemplo “vendasEntities”)        Apagar registos
que herda de uma classe da EntityFramework
chamada ObjectContext, que a classe primária e         Para apagar um registo é necessário seleccionar
responsável de gerir a informação como                 o registo correcto, neste caso usando uma
objectos e a ligação dos objectos aos dados.           Lambda Expression, e caso o resultado seja
                                                       válido, executamos o método DeleteObject(),
Inserir registos                                       indicando o registo a apagar.

Para inserir novos registos, neste caso um novo        Finalmente gravamos as alterações na base de
cliente, criamos uma nova instância da                 dados.
respectiva classe, definindo as suas
propriedades,     que      correspondem     aos
respectivos campos. Depois adicionamos o
objecto através do método AddObject() e,
                                                        Using context As New vendasEntities
finalmente,      executamos        o     método
SaveChanges() que irá efectuar as respectivas
                                                          ' Procura o registo com o número de
alterações, neste caso inserir um registo, na
                                                          ' cliente (ID) igual a 1
base de dados.
                                                         Dim cliente = context.clientes.Where(
                                                                          Function(c) c.id = 1).
                                                                          FirstOrDefault()

  Using context As New vendasEntities
                                                            If cliente IsNot Nothing Then
                                                                context.clientes.DeleteObject(cliente)
       ' Cria um novo cliente
                                                                context.SaveChanges()
       Dim cliente As New clientes With
                                                            Else
             {
                                                                   MessageBox.Show(
                   .nome = "Rui Paulo",
                                                                      "Número de cliente inválido")
                   .morada = "Lisboa",
                                                            End If
                   .datanascimento =
                    New DateTime(1980, 10, 31)
                                                        End Using
             }



                                                  20
VISUAL (NOT) BASIC
                                                                                I n tro d u ç ã o a o E n ti ty Fra m e wo rk


Modificar Registos
                                                          Using context As New vendasEntities

Para modificar um registo, e à semelhança da
                                                              Dim listaClientes =
operação anterior, é necessário seleccionar o
                                                                     From c In context.clientes
registo. Neste exemplo utilizamos LINQ to
                                                                  Where c.morada.Contains("Lisboa") And
Entities para fazer essa selecção. Depois,
                                                                     c.datanascimento <
modificamos o que for para modificar e
                                                                                  New DateTime(1985, 1, 1)
finalmente gravamos as alterações.
                                                                     Select c


 Using context As New vendasEntities                          For Each c As clientes In listaClientes
                                                                     Debug.WriteLine(c.nome)

     Dim cliente =                                            Next

            (From c In context.clientes
             Where c.id = 1                               End Using

             Select c).FirstOrDefault()

                                                         Entre      entidades      existir   normalmente
     If cliente IsNot Nothing Then
                                                         associações, e essas associações (também
            With cliente
                                                         representadas na última imagem), têm algo que
                .nome = "Rui Paulo"
                                                         se designa por Navigation Properties. As
                .morada = "Setúbal"
                                                         Navigation Properties permitem uma navegação
                .datanascimento =
                                                         bidireccional entre entidades, de acordo com as
                 New DateTime(1979, 10, 31)
                                                         suas associações. Isto é algo bastante prático
            End With
                                                         pois permite-nos criar queries entre várias
            context.SaveChanges()
                                                         entidades usando LINQ to Entities.
     Else
            MessageBox.Show(
                                                         O seguinte exemplo mostra esta abordagem,
            "Número de cliente inválido")
                                                         definindo depois o resultado como DataSource
     End If
                                                         num controlo DataGridView.
 End Using

                                                         NOTA: Se utilizar uma base de dados anexa ao
                                                          Using context As New vendasEntities

Listar Registos
                                                              Dim listaClientes =
                                                                     From c In context.clientes
A listagem de registo é também muito
                                                                     Join m In context.movimentos
semelhante às operações anteriores. Neste
                                                                         On m.clienteid Equals c.id
exemplo, usando LINQ to Entities, vamos
                                                                     Join p In context.produtos
seleccionar todos os registo com base num
                                                                         On m.produtoid Equals p.id
critério, para uma variável do tipo IQueryable(Of
                                                                     Select m.datavenda,
T), e depois efectuamos um ciclo para mostrar
os resultados obtidos.


                                                    21
VISUAL (NOT) BASIC
I n tro d u ç ã o a o E n ti ty Fra m e wo rk


             Select m.datavenda,                                    especiais), etc
                       c.nome,
                       p.produto,                                   Estas são apenas algumas, das muitas
                       m.preco                                      vantagens, que nos devem fazer de uma vez por
                                                                    todas, deixar de usar SqlCommands,
    Me.DataGridView1.DataSource = listaClientes                     SqlConnections, DataSets, etc.
  End Using




projecto (AttachDb), a base de dados é copiada
para     as     pastas     Debug/Release.     Pode                  Alguns recursos interessantes:
seleccionar no menu Project a opção Show All
Files e verificar as alterações nessa localização.                  Data Developer Center
                                                                    http://msdn.microsoft.com/en-us/data/ef.aspx

CONCLUSÃO                                                           Data Access Hands-on Labs
                                                                    http://msdn.microsoft.com/en-
Como foi possível ver ao longo do artigo, que                       us/data/gg427655.aspx
abordou de uma forma muito superficial algumas
das funcionalidades deste ORM, o Entity                             ADO.NET team blog
Framework é uma excelente opção para se                             http://blogs.msdn.com/b/adonet/
trabalhar com bases de dados.
                                                                    Julie Lerman's Blog
É simples de utilizar, permite-nos trabalhar                        http://thedatafarm.com/blog/
apenas com objectos e com intellisense, resolve
inúmeros problemas que são habituais quando
trabalhamos directamente com a base de dados
(formatos de datas, números, caracteres




 AUTOR

                       Escrito por Jorge Paulino
                       Exerce funções de analista-programador numa multinacional sediada em Portugal. É formador e ministra
                       cursos de formação em tecnologias Microsoft .NET e VBA. É Microsoft Most Valuable Professional (MVP),
                       em Visual Basic, pela sua participação nas comunidades técnicas . É administrador da Comunidade
                       Portugal-a-Programar e membro de várias comunidades (PontoNetPT, NetPonto, MSDN, Experts-
                       Exchange, CodeProject, etc). É autor do blog http://vbtuga.blogspot.com - twitter @vbtuga




                                                               22
A PROGRAMAR

Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )
Começo com este artigo uma série de artigos             sobre PF por exemplo). Como já há vários
relacionados com a Programação Funcional em             artigos sobre PF em diversas linguagens, como
Perl.                                                   Python, Scheme, Haskell (recomendo que os
                                                        leiam), deixo aqui a sugestão a alguém, para
Nesta série de artigos pretendo demonstrar              redigir um artigo teórico e agnóstico (em relação
algumas das capacidades do Perl para utilização         a linguagens de programação) sobre
com o paradigma de Programação Funcional.               Programação Funcional.

Não pretendo ensinar nem as bases da                        Umas das principais
Programação Funcional, nem do Perl. Vou abrir               características do Perl
excepções quando se tratarem de aspectos mais
avançados e/ou muito relacionados com a                 (...) é não obrigar o
própria Programação Funcional. A compreensão            programador a utilizar (...)
elementar do Perl e da Programação Funcional            mas sim permitir ao
é um requisito para a compreensão destes
artigos contudo tudo será explicado de forma a          programador utilizar o que
permitir que um principiante possa compreender          quiser quando quiser
tudo e quem tiver dúvidas poderá contactar-me
para as esclarecer.                                     Algumas das funcionalidades elementares das
                                                        linguagens funcionais são as funções anónimas
Umas das principais características do Perl, em         e as closures. O Perl tem ambas as features.
seguimento do mantra da sua comunidade
(«There's more than one way to do it»), é não           Uma das alterações que o Perl 5.1 2 trouxe foi
obrigar o programador a utilizar, ou escolher um        uma função chamada say. O say é basicamente
paradigma de programação, mas sim permitir ao           um print que adiciona um newline à string que
programador utilizar o que quiser quando quiser,        queremos imprimir (poupa-nos pelo menos 4
ficando ao cuidado dele ter os cuidados                 caracteres).
necessários para que o código seja útil e siga
boas práticas de programação. Há quem                   Qualquer uma das seguintes linhas de código
concorde com esta filosofia, há quem não                vai imprimir isolado numa linha a string: «Hello
concorde, mas a filosofia do Perl e da sua              world!»:
comunidade não é o âmbito deste artigo.
                                                         print "Hello world!n";
Um dos muitos paradigmas de programação que              print "Hello world!"."n";
são possíveis utilizar em Perl é a Programação           print "Hello world!", "n";
Funcional (PF). Contudo não cabe a este artigo           say "Hello world!";
explicar a PF. Por isso sugiro que antes de
prosseguirem na leitura deste artigo leiam pelo
menos uma curta explicação do que é PF (os
primeiros parágrafos do artigo da Wikipedia

                                                   23
A PROGRAMAR
Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )


Para demonstrar a utilização de funções                                  utilização nas "dispach tables":
anónimas decidi criar uma implementação da
função say que permite definir antes da sua                               my %lingua = (   #dispach table
utilização como queremos que a string seja                                     "pt" => sub { return "Olá mundo!" },
formatada:                                                                     "es" => sub { return "Hola mundo!" },
                                                                               "en" => sub { return "Hello world!" },
  sub say {        #definição da função say                                    "fr" => sub { return "Bonjour monde!" },
       my ($string, $format) = @_;                                            );
       my $str = $format->($string);
       print $str;                                                        sub dispach {
  }                                                                            my $l = shift;
  my   $format       =   sub    {       #função      anónima   de                  if(defined   $lingua{$l}     &&   exists
  formatação da string                                                    $lingua{$l}) {
             my $str = shift;                                                      my $str = $lingua{$l}->();
             return $str."n";                                                     print $str."n";
       };                                                                      }
  say("Hello world!", $format);                                                else {
                                                                                   print "Erro: lingua desconhecida!n";
                                                                               }
Explicação do código do exemplo anterior:                                 }
                                                                          dispach("fr");
Primeiro começamos por definir a função say,
como definiríamos qualquer outra função em
Perl. Depois definimos a função anónima de
formatação, e atribuímos essa função a uma
variável (que guarda uma referência para                                 Explicação do código do exemplo anterior:
código) para que possa ser passada de forma
visualmente mais limpa à função say                                      Começou por ser definido uma hash table que,
(poderíamos também ter definido a função                                 como chaves contém, as opções válidas de
anónima, na invocação de say mas faria com                               línguas que queremos utilizar na impressão de
que o código fosse muito menos legível).                                 uma saudação e como valores, tem funções
                                                                         anónimas que imprimem uma saudação na
                                                                         língua representada pela sua chave na hash
Qual a utilidade das funções anónimas?                                   table.

As utilidades são diversas. E vão desde a                                Isto poderia ter sido feito definindo
utilização das funções anónimas para poder                               individualmente funções "regulares", criando
modificar o comportamento de uma função que                              variáveis que eram referências para cada uma
tenha sido criada para poder permitir essa                               dessas funções e utilizando essas variáveis
alteração. Há quem utilize isto para poder por                           como valores a utilizar na hash table.
exemplo poder voltar a correr código que tinha
sido serializado. E passam pela utilização em                            Mas isso traria imediatamente dois problemas:
"dispach tables". Uma outra utilidade é a                                aumentaria a quantidade de código necessário e
                                                                         este artigo tem um limite de caracteres; não

                                                                    24
A PROGRAMAR
                                                                     Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )


utilizaria funções anónimas, que é o objectivo               solução escale para mais opções de línguas,
deste exemplo ;).                                            sem qualquer alteração e atinge melhor vários
                                                             dos objectivos da utilização de funções na
Para além de isso, o que é pretendido neste                  programação: conter/isolar os problemas de
exemplo, é algo tremendamente simples que                    forma a simplificar a sua resolução, facilitar a
pode perfeitamente ser feito utilizando funções              compreensão do código.
anónimas, sem se aumentar a dificuldade
relevante da sua compreensão como um todo e
em parte.                                                    No próximo, artigo vou falar da segunda das
                                                             principais capacidades do Perl para a
                                                             Programação Funcional de que falei antes, as
A opção por esta solução, em vez de a utilização             closures.
de um encadeamento maior de if-elsif, ou de um
switch-case (também maior) permite que a




                             (...) permite que a solução
                         escale para mais opções de
                         línguas, sem qualquer alteração e
                         atinge melhor vários dos
                         objectivos da utilização de
                         funções na programação (...)


 AUTOR

                Escrito por Diogo Constantino
                é Consultor na área as tecnologias licenciadas como Software Livre, com aproximadamente vários anos
                de experiência profissional, especializado em desenvolvimento com Perl.
                Larga experiência na área de sistemas, engenharia e de operações de redes de telecoms, tendo
                desenvolvido, mantido e utilizado ferramentas para diversas telecoms nestas áreas.
                Conhecimentos em tecnologias como Perl, Python, PHP, MySQL, GNU/Linux, C, HTML, CSS, Javascript,
                GNU/Linux. Tendo tido ainda contacto profissional com tecnologias como Switchs, equipamentos de
                routing, firewalling e switching de diversos fabricantes, diversos sistemas *nix e diversas outras
                ferramentas e tecnologias comuns em sistemas *nix e/ou utilizadas em empresas de telecomunicações,
                redes e web. Relativamente conhecido advogado da causa do Software Livre em diversas comunidades.
                Sócio da Associação Nacional para o Software Livre e da Associação Portuguesa de Programadores de
                Perl.




                                                        25
COMUNIDADE NETPONTO

B a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m
Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)
Neste artigo pretendo mostrar o que é o                  System.ComponentModel. Esta classe permite-
BackgroundWorker e vou exemplificar como se              nos ajudar a gerir uma tarefa numa thread
deve proceder à sua implementação usando a               separada da thread principal sem termos de nos
tecnologia WPF na versão .Net Framework 4.               preocupar com a inicialização e gestão da thread
                                                         onde vamos executar a tarefa.
Suponhamos:
                                                         As propriedades a ter em conta são:
“Tenho um algoritmo complexo de Optimização
 Combinatória que irá ter como parâmetro de              CancellationPending
 entrada um objecto do tipo World. Classe que            Permite obter se a tarefa foi cancelada.
 define toda a estrutura de dados da minha
 aplicação e no final retorna o objecto World com        WorkerReportsProgress
 as alterações realizadas pelo algoritmo.”               Permite obter e definir se o BackgroundWorker
                                                         vai reportar o seu progresso da tarefa.
Esta geração vai implicar que tenhamos pelo
menos três passos:                                       WorkerSupportsCancellation
1 . A partir do objecto World vamos criar a              Permitir obter e definir se o BackgroundWorker
estrutura de dados do algoritmo;                         vai permitir cancelar a tarefa.
2. Gera-se o algoritmo a partir dos dados
recebidos;                                               Os métodos a ter em conta são:
3. Depois de gerar o algoritmo é preciso
converter o resultado de forma a reflectir no            RunWorkerAsync
World o resultado do algoritmo;                          Permite iniciar a tarefa.
                                                         Existem duas assinaturas deste método. Uma
Enquanto estes três passos estão a decorrer, eu          delas não tem argumento, a outra que o tem
quero ser informada sobre o progresso da                 utiliza-o na execução da tarefa.
geração do algoritmo e pretendo ter a
capacidade de a cancelar.                                CancelAsync
                                                         Permite cancelar a tarefa e consequentemente o
Este cenário é um dos muitos cenários onde o             BackgroundWorker irá terminar.
BackgroundWorker pode ser implementado.                  Para que seja possível cancelar a tarefa é
Outros exemplos reais são a leitura de ficheiros         necessário       que         a     propriedade
extensos, aceder a base de dados para efectuar           WorkerSupportsCancellation tenha o valor de
o carregamento de dados, fazer o load de                 verdade true.
imagens e gerar relatórios.
                                                         ReportProgress
Antes de passarmos à implementação vou dar               Permite reportar o progresso da tarefa em dado
uma breve apresentação teórica:                          momento.
                                                         Para que o progresso seja reportado é
Um BackgroundWorker é uma classe contida no              necessário que o WorkerReportsProgress tenha

                                                    26
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile
LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile

Weitere ähnliche Inhalte

Was ist angesagt? (20)

Revista programar 33
Revista programar 33Revista programar 33
Revista programar 33
 
Revista Programar 01
Revista Programar 01Revista Programar 01
Revista Programar 01
 
Revista programar 22
Revista programar 22Revista programar 22
Revista programar 22
 
Revista programar 17
Revista programar 17Revista programar 17
Revista programar 17
 
Revista Programar 42
Revista Programar 42Revista Programar 42
Revista Programar 42
 
Revista programar 11
Revista programar 11Revista programar 11
Revista programar 11
 
Revista programar 34
Revista programar 34Revista programar 34
Revista programar 34
 
LibreOffice Magazine 25
LibreOffice Magazine 25LibreOffice Magazine 25
LibreOffice Magazine 25
 
LibreOffice Magazine 14
LibreOffice Magazine 14LibreOffice Magazine 14
LibreOffice Magazine 14
 
Revista programar 37
Revista programar 37Revista programar 37
Revista programar 37
 
Revista Espirito Livre 009 Dezembro09
Revista Espirito Livre 009 Dezembro09Revista Espirito Livre 009 Dezembro09
Revista Espirito Livre 009 Dezembro09
 
LibreOffice Magazine 21
LibreOffice Magazine 21LibreOffice Magazine 21
LibreOffice Magazine 21
 
Revista espirito livre_013_abril2010
Revista espirito livre_013_abril2010Revista espirito livre_013_abril2010
Revista espirito livre_013_abril2010
 
LibreOffice Magazine 17
LibreOffice Magazine 17LibreOffice Magazine 17
LibreOffice Magazine 17
 
LIVRO PROPRIETÁRIO - METODOLOGIAS DE DESENVOLVIMENTO DE SISTEMAS
LIVRO PROPRIETÁRIO - METODOLOGIAS DE DESENVOLVIMENTO DE SISTEMASLIVRO PROPRIETÁRIO - METODOLOGIAS DE DESENVOLVIMENTO DE SISTEMAS
LIVRO PROPRIETÁRIO - METODOLOGIAS DE DESENVOLVIMENTO DE SISTEMAS
 
LIVRO PROPRIETÁRIO - PROGRAMAÇÃO I
LIVRO PROPRIETÁRIO - PROGRAMAÇÃO ILIVRO PROPRIETÁRIO - PROGRAMAÇÃO I
LIVRO PROPRIETÁRIO - PROGRAMAÇÃO I
 
Revista programar 28
Revista programar 28Revista programar 28
Revista programar 28
 
Revista programar 25
Revista programar 25Revista programar 25
Revista programar 25
 
Revista Linux 4
Revista Linux 4Revista Linux 4
Revista Linux 4
 
Artigo Blender 3 D
Artigo Blender 3 DArtigo Blender 3 D
Artigo Blender 3 D
 

Andere mochten auch

Revista espirito livre_017_agosto2010
Revista espirito livre_017_agosto2010Revista espirito livre_017_agosto2010
Revista espirito livre_017_agosto2010Filipe Bezerra Sousa
 
Coordinación y docencia TIC
Coordinación y docencia TICCoordinación y docencia TIC
Coordinación y docencia TICDLUNAMEJ
 
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TIC
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TICUN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TIC
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TICSarahiJaramillo
 
Efectos de las herramientas
Efectos de las herramientasEfectos de las herramientas
Efectos de las herramientasruthmariana
 
4. tema iv. costeo directo. capítulo 25
4. tema iv. costeo directo. capítulo 254. tema iv. costeo directo. capítulo 25
4. tema iv. costeo directo. capítulo 25Rafael Verde)
 
pPortafolio de presentación 4
pPortafolio de presentación   4pPortafolio de presentación   4
pPortafolio de presentación 4angelrc8
 
Desarrolloembarazo
DesarrolloembarazoDesarrolloembarazo
DesarrolloembarazoFanny Adonay
 
Dialeto Novo Profissional / Mariana Martins
Dialeto Novo Profissional / Mariana MartinsDialeto Novo Profissional / Mariana Martins
Dialeto Novo Profissional / Mariana Martinsmahmartins
 
1. tema i. costos por procesos capítulo 13
1. tema i. costos por procesos capítulo 131. tema i. costos por procesos capítulo 13
1. tema i. costos por procesos capítulo 13Rafael Verde)
 
El libro azul
El libro azulEl libro azul
El libro azululisbro
 
RESEÑA DE LA I.E. 3014 - LEONCIO PRADO
RESEÑA DE LA I.E. 3014 - LEONCIO PRADORESEÑA DE LA I.E. 3014 - LEONCIO PRADO
RESEÑA DE LA I.E. 3014 - LEONCIO PRADONancy Portillo
 
1. tema i. costos por proceso.
1. tema i. costos por proceso.1. tema i. costos por proceso.
1. tema i. costos por proceso.Rafael Verde)
 

Andere mochten auch (20)

Revista espirito livre_001
Revista espirito livre_001Revista espirito livre_001
Revista espirito livre_001
 
Revista programar 24
Revista programar 24Revista programar 24
Revista programar 24
 
Revista espirito livre_017_agosto2010
Revista espirito livre_017_agosto2010Revista espirito livre_017_agosto2010
Revista espirito livre_017_agosto2010
 
Paola mapa 2
Paola mapa 2Paola mapa 2
Paola mapa 2
 
Coordinación y docencia TIC
Coordinación y docencia TICCoordinación y docencia TIC
Coordinación y docencia TIC
 
Aprovacao ccjc[1]
Aprovacao ccjc[1]Aprovacao ccjc[1]
Aprovacao ccjc[1]
 
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TIC
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TICUN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TIC
UN MODELO PARA INTEGRAR LAS TIC AL CURRÍCULO ESCOLAR INFRAESTRUCTURA TIC
 
Efectos de las herramientas
Efectos de las herramientasEfectos de las herramientas
Efectos de las herramientas
 
4. tema iv. costeo directo. capítulo 25
4. tema iv. costeo directo. capítulo 254. tema iv. costeo directo. capítulo 25
4. tema iv. costeo directo. capítulo 25
 
ANTIVIRUS
ANTIVIRUSANTIVIRUS
ANTIVIRUS
 
pPortafolio de presentación 4
pPortafolio de presentación   4pPortafolio de presentación   4
pPortafolio de presentación 4
 
Fantrack guarana
Fantrack guaranaFantrack guarana
Fantrack guarana
 
Desarrolloembarazo
DesarrolloembarazoDesarrolloembarazo
Desarrolloembarazo
 
Dialeto Novo Profissional / Mariana Martins
Dialeto Novo Profissional / Mariana MartinsDialeto Novo Profissional / Mariana Martins
Dialeto Novo Profissional / Mariana Martins
 
1. tema i. costos por procesos capítulo 13
1. tema i. costos por procesos capítulo 131. tema i. costos por procesos capítulo 13
1. tema i. costos por procesos capítulo 13
 
Qué son las tics.1
Qué son las tics.1Qué son las tics.1
Qué son las tics.1
 
El libro azul
El libro azulEl libro azul
El libro azul
 
Hamaad Resume
Hamaad ResumeHamaad Resume
Hamaad Resume
 
RESEÑA DE LA I.E. 3014 - LEONCIO PRADO
RESEÑA DE LA I.E. 3014 - LEONCIO PRADORESEÑA DE LA I.E. 3014 - LEONCIO PRADO
RESEÑA DE LA I.E. 3014 - LEONCIO PRADO
 
1. tema i. costos por proceso.
1. tema i. costos por proceso.1. tema i. costos por proceso.
1. tema i. costos por proceso.
 

Ähnlich wie LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile

Ähnlich wie LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile (20)

Revista programar 23
Revista programar 23Revista programar 23
Revista programar 23
 
Revista programar 19
Revista programar 19Revista programar 19
Revista programar 19
 
Revista programar 17
Revista programar 17Revista programar 17
Revista programar 17
 
Revista programar 16
Revista programar 16Revista programar 16
Revista programar 16
 
Revista programar 18
Revista programar 18Revista programar 18
Revista programar 18
 
Revista programar 2
Revista programar 2Revista programar 2
Revista programar 2
 
Revista programar 10
Revista programar 10Revista programar 10
Revista programar 10
 
Revista espirito livre_002
Revista espirito livre_002Revista espirito livre_002
Revista espirito livre_002
 
LibreOffice Magazine 26
LibreOffice Magazine 26LibreOffice Magazine 26
LibreOffice Magazine 26
 
Revista espirito livre_005_agosto09
Revista espirito livre_005_agosto09Revista espirito livre_005_agosto09
Revista espirito livre_005_agosto09
 
Revista programar 2
Revista programar 2Revista programar 2
Revista programar 2
 
Dossier 15 mcc_v_0.9.1_pt
Dossier 15 mcc_v_0.9.1_ptDossier 15 mcc_v_0.9.1_pt
Dossier 15 mcc_v_0.9.1_pt
 
Dossier 15M.cc PORTUGUES v.0.91
Dossier 15M.cc PORTUGUES v.0.91Dossier 15M.cc PORTUGUES v.0.91
Dossier 15M.cc PORTUGUES v.0.91
 
Seminário Web 20 - Info 09/2007
Seminário Web 20 - Info 09/2007Seminário Web 20 - Info 09/2007
Seminário Web 20 - Info 09/2007
 
Revista programar 30
Revista programar 30Revista programar 30
Revista programar 30
 
Revista programar 55
Revista programar 55Revista programar 55
Revista programar 55
 
curso-219506-aula-03-2d66-completo.pdf
curso-219506-aula-03-2d66-completo.pdfcurso-219506-aula-03-2d66-completo.pdf
curso-219506-aula-03-2d66-completo.pdf
 
Revista espirito livre_009_dezembro09
Revista espirito livre_009_dezembro09Revista espirito livre_009_dezembro09
Revista espirito livre_009_dezembro09
 
Revista programar 12
Revista programar 12Revista programar 12
Revista programar 12
 
Revista programar 21
Revista programar 21Revista programar 21
Revista programar 21
 

Mehr von Filipe Bezerra Sousa

Mehr von Filipe Bezerra Sousa (13)

Como criar metas por fred graef
Como criar metas por fred graefComo criar metas por fred graef
Como criar metas por fred graef
 
Estudo de produtividade com eclipse
Estudo de produtividade com eclipseEstudo de produtividade com eclipse
Estudo de produtividade com eclipse
 
Revista espirito livre_035_fevereiro2012
Revista espirito livre_035_fevereiro2012Revista espirito livre_035_fevereiro2012
Revista espirito livre_035_fevereiro2012
 
Revista programar 31
Revista programar 31Revista programar 31
Revista programar 31
 
Revista programar 29
Revista programar 29Revista programar 29
Revista programar 29
 
Revista programar 27
Revista programar 27Revista programar 27
Revista programar 27
 
Revista espirito livre_0019_outubro2010
Revista espirito livre_0019_outubro2010Revista espirito livre_0019_outubro2010
Revista espirito livre_0019_outubro2010
 
Revista espirito livre_016_julho2010
Revista espirito livre_016_julho2010Revista espirito livre_016_julho2010
Revista espirito livre_016_julho2010
 
Revista espirito livre_015_junho2010
Revista espirito livre_015_junho2010Revista espirito livre_015_junho2010
Revista espirito livre_015_junho2010
 
Revista espirito livre_014_maio2010
Revista espirito livre_014_maio2010Revista espirito livre_014_maio2010
Revista espirito livre_014_maio2010
 
Revista espirito livre_012_marco2010
Revista espirito livre_012_marco2010Revista espirito livre_012_marco2010
Revista espirito livre_012_marco2010
 
Revista espirito livre_011_fevereiro10
Revista espirito livre_011_fevereiro10Revista espirito livre_011_fevereiro10
Revista espirito livre_011_fevereiro10
 
Revista espirito livre_010_janeiro10
Revista espirito livre_010_janeiro10Revista espirito livre_010_janeiro10
Revista espirito livre_010_janeiro10
 

LINQ: Operadores TakeLast, TakeLastWhile, SkipLast e SkipLastWhile

  • 1.
  • 2. Editorial EDITORIAL EQUIPA PROGRAMAR Sempre em movimento… Coordenadores Porque sabemos que parar é morrer, nesta edição da Revista António Silva PROGRAMAR introduzimos várias alterações que achamos importantes Fernando Martins para continuidade deste projecto. Das várias alterações introduzidas, a salta imediatamente à vista, mesmo ao leitor que ainda está somente a ler a Editor página do editorial, é a mudança de design . Em qualquer tipo de António Silva publicação o design influencia o modo como vemos como lemos. Aqui temos que agradecer a todos quantos ajudaram a adaptar este novo design, Design mas especialmente ao Sérgio Alves por toda a parte da idealização e Sérgio Alves (@scorpion_blood) desenho do novo design. Outra alteração, que todavia não será tão notada pelos leitores é a Redacção alteração do software de paginação. Chegamos à conclusão que o Scribus André Lage, Augusto Manzano, Diogo já evoluiu bastante desde a última vez que foi utilizado para paginar a Constantino, Fernando Martins, João Mares, Revista PROGRAMAR e está à altura das nossas necessidades. Assim João Matos, Jorge Paulino, Paulo Morgado, decidimos que não havia necessidade de continuarmos a utilizar um Pedro Aniceto, Ricardo Rodrigues, Ricardo software pago e que trazia vários problemas de leitura a alguns utilizadores Trindade, Sara Silva (dos quais chegamos a receber comentários). Também fizemos várias parcerias com algumas comunidades Contacto portuguesas que estão de algum modo relacionadas com programação, de revistaprogramar@portugal-a-programar.info modo a obter mais e melhores artigos para si. Todavia não estamos fechados a mais parcerias, continuamos abertos a futuros contactos para o Website nosso endereço de correio electrónico, que serão posteriormente analisados http://www.revista-programar.info por toda a equipa. Trazemos também até si, colunas de opinião e colunas direccionadas a ISSN um tema específico. Assim poderá contar que surgirão artigos desse 1 647-071 0 assunto com uma periodicidade específica na sua Revista favorita. Por fim, achamos que estamos prontos para voltar a trazer a Revista PROGRAMAR até si de 2 em 2 meses , e por isso a próxima edição deverá INDICE sair em Fevereiro ao invés de Março como estava programado. 4 Tema de Capa - LINQ Tudo isto para si, que está ler. Esperámos que as alterações sejam bem 11 BYACC recebidas por todos, mas também esperámos opiniões sobre todas estas 18 Introdução ao Entity Framework alterações, mesmo porque as novidades poderão não ficar por aqui, 23 Programação Funcional Perl (Parte I ) contámos ter mais novidades na próxima edição. Por isso não tenha medo 26 BackgroundWorkers em WPF de nos contactar para revistaprogramar@portugal-a-programar.org a dizer o 31 jQuery - O quê, como e porquê? que acha de todas estas alterações. Porque você é importante para nós, 35 Tutorial de Lua (Parte 6) quer as suas opiniões, quer o seu trabalho a divulgar o nosso projecto aos 41 E se amanhã a Apple dominar? seus amigos e colegas, e mais importante a sua preferência que nos 43 SQL em Oracle permite crescer para lhe oferecer algo maior e melhor. 47 Aspectos low-level de 3D 54 Quando se é ! Produtivo A equipa da Revista PROGRAMAR 56 Client Object Model para Silverlight A revista PROGRAMAR é um projecto voluntário, sem fins lucrativos. Todos os artigos são da responsabilidade dos autores, não podendo a revista ou a comunidade ser responsabilizada por alguma imprecisão ou erro. Para qualquer dúvida ou esclarecimento poderá sempre contactar-nos. 2
  • 3. Noticias NOTICIAS U p l o a d Li s b o a e U p l o a d Li s b o a Se m i n á ri o Po c ke tPT s o b re Pro 2 0 1 0 te c n o l o gi a s Wi n d o ws Ph o n e O Upload Lisboa é um evento que por si só nomeia a era Encontram-se abertas as inscrições para o 6º Seminário em que estamos. A era da nova comunicação, da troca de PocketPT sobre tecnologias móveis Windows Phone. Este informação no momento, de forma prática e natural, e da ano o seminário será dedicado à nova plataforma móvel da partilha de conhecimentos em rede. O Upload Lisboa Microsoft, e irá incluir várias sessões que irão dar a pretende, mais uma vez, passar a esfera da rede interior e conhecer as funcionalidades do mesmo. global para a esfera da partilha conjunta, física. Será ainda uma excelente oportunidade para os Este evento nasce da necessidade crescente de debate e participantes testarem e verem em primeira mão os novos partilha de conhecimentos sobre a web 2.0, numa altura em equipamentos. que as novas plataformas de comunicação e informação Como tem vindo a acontecer nos anos anteriores a assumem um lugar cada vez mais central na vida de inscrição este ano é gratuita e irá ter lugar no auditório da pessoas e empresas. Hoje, mais que nunca, a partilha Microsoft Portugal no TagusPark em Porto Salvo no através das plataformas sociais na web ocupam um lugar próximo dia 1 8 de Dezembro pelas 1 0h. de destaque na influência na opinião pública e na formação Mais informações e inscrições: de critérios de análise ao que se passa no país e no http://www.mtechseminar.com/201 0/index.htm mundo. São dois dias, 11 e 1 5 de Dezembro, que certamente não irá perder! Mais informações: http://uploadlisboa.com/ SAPO C o d e B i ts 2 0 1 0 1 6 a R e u n i ã o Pre s e n c i a l d a C o m u n i d a d e N e tPo n to De 11 a 1 3 de Novembro de 201 0 decorreu o Sapo No dia 11 /1 2/201 0 será realizada a 1 6ª reunião presencial Codebits 201 0. A comunidade Portugal-a-Programar esteve da comunidade NetPonto, em Lisboa. Nesta sessão, presente, tendo alguns membros efectuado alguns poderá ver duas apresentações presenciais sobre Domain projectos. Este ano, com oferta da comunidade, todos os Driven Design e WP7 & XNA – Let’s play? que participaram e solicitaram, tiveram direito a uma t-shirt Para participar, basta efectuar a inscrição através do site para usar durante o evento. http://netponto-lisboa-dezembro-201 0.eventbrite.com/ A Esta foi a foto de grupo de alguns dos elementos que entrada é gratuita e são realizadas reuniões todos os estiveram presentes (infelizmente não foi possível juntar meses. todos): Para mais informações, consulta de próximas sessões e inscrição: http://netponto.org/ 3
  • 4. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e S ki p La stWh i l e Há algum tempo necessitei de obter os últimos original uma vez e mais três vezes sobre os itens de uma sequência que satisfaziam um itens que satisfazem o critério. Se a sequência determinado critério e, olhando para os original for grande, isto pode consumir muita operadores disponíveis na classe Enumerable, memória e tempo. apercebi-me de que tal operador não existia. Existe ainda um problema adicional quando se A única forma de obter o resultado pretendido usa a variante que usa o índice de item na era inverter a ordem dos itens na sequência, sequência original na avaliação do critério de obter os itens que satisfaziam o critério e inverter selecção (>). Quando se inverte a ordem dos os itens da sequência resultante. itens, os índices destes serão invertidos e o predicado de avaliação do critério de selecção Algo como isto: terá de ter isso em consideração, o que poderá não ser possível se não se souber o número de Sequence itens na sequência original. .Reverse() .TakeWhile(criteria) Tinha de haver uma solução melhor, e é por isso .Reverse(); que eu implementei os Operadores Take Last: TakeLast<TSource>(IEnumerable<TSource>) Parece simples, certo? Primeiro chamamos o método Reverse para produzir uma nova Retorna o número especificado de elementos sequência com os mesmos itens mas na ordem contínuos no fim da sequência. inversa da sequência original, depois chamamos int[] grades = { 59, 82, 70, 56, 92, 98, 85 o método TakeWhile para obter os primeiros }; itens que satisfazem o critério e, finalmente, chamamos novamente o método Reverse para var topThreeGrades = grades recuperar a ordem original dos itens. .OrderBy(grade => grade) .TakeLast(3); O problema desta aproximação é que o método rev memoriza toda a sequência antes de iterar Console.WriteLine("As notas mais altas sobre os seus itens na ordem inversa – e o são:"); código acima usa-o duas vezes. Isto significa iterar sobre todos os itens da sequência original foreach (int grade in topThreeGrades) e memoriza-los, iterar sobre os primeiros itens { que satisfazem o critério e memoriza-los e, Console.WriteLine(grade); finalmente, iterar sobre estes itens para produzir } a sequência final. Se estiveram a contar, chegaram à conclusão de que se iterou sobre todos os itens da sequência 4
  • 5. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* string[] fruits = Este código produz o seguinte resultado: { "maçã", "maracujá","banana", "manga", As notas mais altas são: "laranja", "mirtilo", "uva", "morango" }; 98 var query = fruits 92 .TakeLastWhile((fruit, index) => 85 fruit.Length >= index); */ foreach (string fruit in query) TakeLastWhile<TSource>(IEnumerable<TSou { rce>, Func<TSource, Boolean>) Console.WriteLine(fruit); } Retorna os elementos do fim da sequência para os quais a condição especificada é verdadeira. /* Este código produz o seguinte resultado: string[] fruits = morango { "maçã", "maracujá","banana", "manga", */ "laranja", "mirtilo", "uva", "morango" }; Tendo introduzido os operadores TakeLast, faz var query = fruits todo o sentido introduzido os seus duais: os .TakeLastWhile(fruit => operadores SkipLast: string.Compare("laranja", fruit, true) != 0); SkipLast<TSource>(IEnumerable<TSource>) foreach (string fruit in query) Retorna todos os elementos da sequência à { excepção do número especificado de elementos Console.WriteLine(fruit); contínuos no fim da sequência. } int[] grades = /* { 59, 82, 70, 56, 92, 98, 85 }; Este código produz o seguinte resultado: var lowerGrades = grades maracujá .OrderBy(g => g) uva .SkipLast(3); morango */ Console.WriteLine("Todas as notas excepto as top 3:"); TakeLastWhile<TSource>(IEnumerable<TSou foreach (int grade in lowerGrades) rce>, Func<TSource, Int32, Boolean>) { Console.WriteLine(grade); Retorna os elementos do fim da sequência para } os quais a condição especificada é verdadeira. 5
  • 6. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* SkipLastWhile<TSource>(IEnumerable<TSour Este código produz o seguinte resultado: ce>, Func<TSource, Int32, Boolean>) As notas mais altas, excepto: 56 Retorna todos os elementos da sequência à 59 excepção dos elementos do fim da sequência 70 para os quais a condição especificada é 82 verdadeira. */ int[] amounts = { SkipLastWhile<TSource>(IEnumerable<TSour 5000, 2500, 9000, 8000, ce>, Func<TSource, Boolean>) 6500, 4000, 1500, 5500 }; Retorna todos os elementos da sequência à excepção dos elementos do fim da sequência var query = amounts para os quais a condição especificada é .SkipWhile((amount, index) => amount > verdadeira. index * 1000); int[] grades = foreach (int amount in query) { 59, 82, 70, 56, 92, 98, 85 }; { var lowerGrades = grades Console.WriteLine(amount); .OrderBy(grade => grade) } .SkipLastWhile(grade => grade >= 80); /* Este código produz o seguinte resultado: Console.WriteLine("Todas as notas menores que 5000 80:"); 2500 */ foreach (int grade in lowerGrades) { Console.WriteLine(grade); } IMPLEMENTADO OS OPERADORES TAKELAST /* I mplementando O Operador TakeLast Este código produz o seguinte resultado: Todas as notas menores que 80: O operador TakeLast retorna o número 56 especificado de elementos contínuos do fim de 59 uma sequência e é implementado como o 70 método de extensão TakeLast. */ Para implementar este operador, primeiro começamos por memorizar, pelo menos, o número requerido (count) de itens da sequência 6
  • 7. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e fonte (source) num array que funciona como for (; numOfItems > 0; idx = (idx + 1) % uma memória intermédia (buffer) circular: count, numOfItems--) var sourceEnumerator = { source.GetEnumerator(); yield return buffer[idx]; var buffer = new TSource[count]; } var numOfItems = 0; int idx; Há duas optimizações que ainda podemos fazer. for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++, A primeira é óbvia, se o número de itens numOfItems++) requerido for 0 (zero), retornamos uma { sequência vazia: buffer[idx] = sourceEnumerator.Current; if (count <= 0) { Se o número de itens memorizados return (numOfItems) for inferior ao número requerido System.Linq.Enumerable.Empty<TSource>(); (count), produzimos os itens memorizados: } if (numOfItems < count) A segunda é se a sequência fonte (source) { implementar a interface IList<T>. Os objectos for (idx = 0; idx < numOfItems; idx++) que implementam esta interface têm uma { propriedade Count e acesso indexado aos seus yield return buffer[idx]; itens que nos permite optimizar a produção da } sequência final. yield break; } A produção da sequência final passa por produzir o número de itens requeridos do fim da Em seguida, iteramos pelos restantes itens e lista (ou todos se a lista contiver menos que os vamos os armazenando, de forma circular, na itens requeridos): memória intermédia: int listCount = list.Count; for (idx = 0; sourceEnumerator.MoveNext(); for (int idx = listCount - ((count < idx = (idx + 1) % count) listCount) ? count : listCount); idx < { listCount; idx++) buffer[idx] = { sourceEnumerator.Current; yield return list[idx]; } } Implementando os Operadores E finalmente, iteramos sobre os itens TakeLastWhile memorizados para produzir a sequência final: O operador TakeLastWhile retorna os últimos 7
  • 8. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e elementos contíguos que satisfazem o critério buffer.Add(item); especificado e é implementado como os } métodos de extensão TakeLastWhile. else Para implementar este operador, primeiro { começamos com uma memória intermédia buffer.Clear(); (buffer) vazia e, para cada item que satisfaça o } critério implementado pelo predicado (predicate), } memorizamos esse item. Sempre que ocorrer um item que não satisfaça o critério de selecção, foreach (var item in buffer) a memória intermédia é limpa: { var buffer = new List<TSource>(); yield return item; foreach (var item in source) } { if (predicate(item)) { IMPLEMENTANDO OS OPERADORES buffer.Add(item); SKIPLAST } else Implementando o Operador SkipLast { buffer.Clear(); O operador SkipLast retorna o número } especificado de elementos contínuos do fim de } uma sequência e é implementado como o método de extensão SkipLast. Depois de percorrer toda a sequência fonte Para implementar este operador, começamos (source), produzimos todos os itens, se por memorizar, pelo menos, o número requerido existirem, da memória intermédia: (count) de itens da sequência fonte (source) num array que funciona como uma memória foreach (var item in buffer) intermédia (buffer) circular: { yield return item; var sourceEnumerator = } source.GetEnumerator(); var buffer = new TSource[count]; A diferença para o método que tem em conta o int idx; índice do item no predicado (predicate) de selecção é apenas na invocação deste: for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++) var buffer = new List<TSource>(); { var idx = 0; buffer[idx] = sourceEnumerator.Current; } foreach (var item in source) { Em seguida, iteramos pelos restantes itens da if (predicate(item, idx++)) sequência fonte (source) memorizando { 8
  • 9. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e circularmente cada item e produzindo o item var list = source as IList<TSource>; armazenado anteriormente na mesma posição: if (list != null) idx = 0; { if (count >= list.Count) while (sourceEnumerator.MoveNext()) { { return var item = buffer[idx]; System.Linq.Enumerable.Empty<TSource>(); buffer[idx] = sourceEnumerator.Current; } idx = (idx + 1) % count; // ... } yield return item; } Se o número de itens da sequência fonte (source) for superior ao número de itens a Se o número de itens a excluir for igual ou excluir, produzir a sequência final consiste em superior ao número de itens existentes na produzir todos os itens da sequência fonte sequência fonte (source), o método (source) excepto os últimos count itens: sourceEnumerator.MoveNext() retornará false na primeira iteração do ciclo while e será produzida int returnCount = list.Count - count; uma sequência vazia. for (int idx = 0; idx < returnCount; idx++) Tal como acontecia com o operador TakeLast, { podem-se fazer algumas optimizações. yield return list[idx]; } A primeira é óbvia, se o número de itens requeridos for 0 (zero) ou inferior, retornamos Implementando os Operadores uma sequência equivalente à fonte (source): SkipLastWhile if (count <= 0) O operador SkipLastWhile retorna os últimos { elementos contíguos que satisfazem o critério return source.Select(i => i); especificado e é implementado como os } métodos de extensão SkipLastWhile. Para implementar este operador, primeiro A segunda é se a sequência fonte (source) começamos com uma memória intermédia implementar a interface IList<T>. Os objectos (buffer) vazia e, para cada item que satisfaça o que implementam esta interface têm uma critério implementado pelo predicado (predicate), propriedade Count e acesso indexado aos seus memorizamos esse item. itens que nos permite optimizar a produção da sequência final. Sempre que ocorrer um item que não satisfaça o critério de selecção, a memória intermédia é Se o número de itens a excluir for igual ou limpa e o item que não satisfaz o critério é superior ao número de itens da sequência fonte produzido: (source), retornamos uma sequência vazia: 9
  • 10. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e var buffer = new List<TSource>(); else foreach (var item in source) { { if (buffer.Count > 0) if (predicate(item)) { { foreach (var bufferedItem in buffer) buffer.Add(item); { } yield return bufferedItem; else } { buffer.Clear(); if (buffer.Count > 0) } { yield return item; foreach (var bufferedItem in buffer) } { } yield return bufferedItem; } buffer.Clear(); Conclusão } Como podem ver, implementar este tipo de yield return item; operadores é muito fácil, pelo que, não se deve } evitar a sua implementação sempre que se } justifique. Implementar um específico para a nossa aplicação pode significar uma melhor A diferença para o método que tem em conta o legibilidade do código e até um aumento de índice do item no predicado (predicate) de performance. selecção é apenas na invocação deste: Podem encontrar a implementação completa destes operadores (e outros) no meu projecto de var buffer = new List<TSource>(); utilitários e operadores para LINQ no CodePlex: var idx = 0; PauloMorgado.Linq. foreach (var item in source) Recursos { O meu website: http://PauloMorgado.NET/ if (predicate(item, idx++)) Livro “LINQ Com C#” { PauloMorgado.Linq buffer.Add(item); Classe Enumerable } Métodos de extensão AUTOR Escrito por Paulo Morgado É licenciado em Engenharia Electrónica e Telecomunicações (Sistemas Digitais) pelo Instituto Superior de Engenharia de Lisboa e Licenciado em Engenharia Informática pela Faculdade de Ciências e Tecnologia da Universidade Nova de Lisboa. Pelo seu contributo para a comunidade de desenvolvimento em .NET em língua Portuguesa, a Microsoft premeia-o com o prémio MVP (C#) desde 2003. É ainda co-autor do livro “LINQ Com C#” da FCA. 10
  • 11. A PROGRAMAR BYAC C No artigo anterior adquirimos algumas noções eles seguem a gramática que ele define. Se o sobre flex e vimos como implementar um objectivo do parser for só verificar que um certo scanner simples. Relembrando, o flex é um ficheiro, por exemplo um ficheiro xml, segue a gerador de analisadores lexicais ou scanners, e especificação da linguagem, podemos não ter o byacc é um gerador de parsers. Usados em interesse nenhum em saber o valor de qualquer conjunto permitem escrever aplicações bastante token. A nossa calculadora no entanto, precisa sofisticadas, mas no nosso artigo limitamo-nos a de produzir resultados, portanto necessita de considerar uma calculadora simples, servindo saber o valor de cada token NUMBER que como exemplo introdutório. Agora que temos o recebe. O parser define os tokens e o tipo de scanner para a nossa calculadora escrito valores que lhes podem estar associados na podemos começar a considerar o parser. zona das definições, sempre que precisa de um token novo ele chama o scanner com o resto do Um ficheiro byacc tem a mesma estrutura que o input que falta analisar. Vejamos a definição dos flex, já que o analisador lexical em que o flex se tokens para a nossa calculadora: baseia, o lex, copiou a sua estrutura do yacc, o gerador de parsers em que o byacc se baseia. %union { Como tal o nosso ficheiro byacc vai ser algo double d; deste género: }; definições %token<d> NUMBER %token NL %% %left '+' '-' gramática %left '*' '/' %right '^' %% %nonassoc UMINUS int main() { %% yyparse(); } ... %% Comecemos por considerar como é que o parser e o scanner funcionam em conjunto. Um parser int main() recebe tokens e verifica se esses tokens estão a { seguir uma gramática. O que nós estávamos a yyparse(); retornar no scanner, o NUMBER e o NL são } esses tokens. Os tokens podem ter um valor associado ou não. O que o parser faz é ver se 11
  • 12. A PROGRAMAR BYAC C A primeira coisa que encontramos é uma %union, seguida da declaração de dois tokens, %% NUMBER e NL. A %union serve para indicar expr_list : expr NL { std::cout tipos que queiramos associar a tokens e << $1 << std::endl; } eventualmente a elementos da gramática. Ao | expr_list expr NL { escrevermos %token<d> NUMBER estamos a std::cout << $2 << std::endl; } indicar que para além de NUMBER ser um ; token, tem um valor associado do tipo d, neste caso double. Isto vai ser importante quando expr : NUMBER { $$ = $1; } passarmos para a gramática e é por esta razão | '-' expr %prec UMINUS { $$ = que no scanner passávamos o número que -$2; } tínhamos lido ao yylval.d antes de retornarmos o | expr '+' expr { $$ = token. A informação da union e dos tokens que $1+$3; } escrevermos nesta secção vai servir para o | expr '-' expr { $$ = $1- byacc gerar o header ao qual o nosso scanner $3; } fez #include e que permite ao scanner e ao | expr '*' expr { $$ = parser comunicarem entre si. O '+', '-', '*', '/', '^' e $1*$3; } UMINUS também são tokens mas aqui para | expr '/' expr { $$ = além de indicarmos que são tokens estamos a $1/$3; } indicar a associatividade dos operadores, um | expr '^' expr { $$ = conceito que o leitor deverá conhecer, mas que pow($1, $3); } abordaremos com maior profundidade na | '(' expr ')' { $$ = $2; gramática. } ; %{ #include <iostream> #include <cmath> %% %} int main() { %union { yyparse(); double d; } }; Esta versão do parser introduz a gramática, mas %token<d> NUMBER comecemos por observar as diferenças na %token NL secção das definições. Podemos ver primeiro que a introdução de código C/C++ se processa %left '+' '-' da mesma forma que no scanner. Em seguida %left '*' '/' temos a instrução, %type<d> expr, expr não é %right '^' um token, é outro símbolo da gramática mas %nonassoc UMINUS ainda assim tem um tipo, portanto temos que o indicar. %type<d> expr Uma gramática, tal como a gramática da língua 12
  • 13. A PROGRAMAR BYAC C portuguesa, serve para nos indicar a estrutura faz sentido criar várias produções para um stmt, da linguagem, quais as composições de já que um stmt pode ser várias coisas. Neste elementos que são válidas ou não de acordo caso, um while, um if, um bloco, e continuando com a linguagem. É fácil de ver como isto é útil teríamos um for, um switch, um do while, etc. para um compilador. A nossa calculadora tem Sendo usual a existência de várias produções uma gramática muito simples, mas ainda assim com a mesma cabeça, o byacc permite usar a tem-la, portanto temos que compreender alguns seguinte sintaxe, com significado equivalente, princípios sobre gramáticas. As gramáticas são para aumentar a legibilidade: um conjunto de regras, às quais chamamos stmt : WHILE expression stmt produções, constituídas por uma cabeça e um | IF expression stmt corpo. Por exemplo, | IF expression stmt ELSE stmt | block stmt : WHILE expression stmt; ... ; é uma produção, com cabeça stmt e corpo WHILE expression stmt. A cabeça indica-nos Se quiséssemos escrever um parser para uma uma construção da gramática e o corpo como linguagem de programação, tínhamos de ter ela é composta. Os elementos duma gramática uma forma de relacionar as várias regras, por dividem-se em símbolos terminais e não outras palavras uma gramática necessita de terminais, sendo os terminais, para efeitos deste uma estrutura. A forma de criar essa estrutura é artigo, os tokens que o scanner envia e os não- criando um símbolo não terminal inicial ao qual terminais as cabeças de produções, ou seja todos os outros estão subordinados. Pode ajudar símbolos que podem ser produzidos através pensar na estrutura da gramática como uma doutros símbolos. árvore na qual o símbolo não terminal inicial é a raiz, os outros não terminais são nós e os Por clareza, usamos maiúsculas para terminais são as folhas. representar terminais e minúsculas para não terminais, logo, no exemplo acima, stmt e %% expression são símbolos não terminais enquanto que o WHILE é terminal. Um símbolo terminal program : list não pode ser obtido através da junção de outros ; símbolos, portanto só pode aparecer em corpos de produções. Um não terminal por outro lado list : statement pode ser derivado de terminais e outros não | list statement terminais, logo pode aparecer tanto na cabeça ; como no corpo duma produção. Um símbolo não terminal pode, e habitualmente, tem várias statement : declaration definições. Pegando no exemplo anterior e | function expandindo, obtemos, ; stmt : WHILE expression stmt; declaration : type identifier stmt : IF expression stmt; | type identifier '=' stmt : IF expression stmt ELSE stmt; expression stmt : block; ; ... 13
  • 14. A PROGRAMAR BYAC C s : x | y type : INT ; | DOUBLE x : A B C ; | CHAR y : A B C ; ; Este caso é óbvio, temos duas produções function : type identifier '(' arg_list ')' diferentes com o mesmo corpo, o parser não block sabe qual deve usar quando recebe os três ; tokens. O mesmo se passa nos casos seguintes. block : '{' stmt_list '}' s : x ; | y ; stmt_list : stmt x : A B C ; | stmt_list stmt y : A z C ; ; z : B ; ... %% s : x | y Acima temos um esqueleto de uma linguagem ; muito simplificada, ainda com vários não x : A B C ; terminais sem produções associadas, mas basta y : z C ; para termos uma noção da estrutura duma z : A B ; gramática. Qualquer que seja o programa escrito para esta linguagem, se ele estiver O byacc só tem um token de lookahead, ou seja, sintacticamente correcto deve ser possível partir no caso abaixo ele não consegue decidir se o de program e derivar todos os elementos que o que recebeu foi o x ou o y porque no momento compõem. Neste caso program é o símbolo de escolher a produção ele só sabe que o se inicial da gramática, e indicamos isso ao byacc segue é o token C. Como existem dois casos colocando-o como a primeira produção do com o token C, ele não sabe o que fazer. Isto ficheiro. não é um problema com a gramática, é uma Já vimos nos exemplos anteriores que as limitação do byacc. produções podem ser recursivas, o corpo duma produção pode conter o mesmo não terminal s : x C D que é a cabeça. A recursividade é necessária e | y C F algo que o byacc processa muito eficientemente, ; mas usada sem cuidado é uma das coisas que x : A B; introduz conflictos na gramática. Um conflicto y : A B; surge quando o parser não sabe que regra usar para uma determinada sequência de tokens. Um O mesmo não ocorre no caso seguinte. Nesta exemplo segue-se: situação ele consegue saber que produção usar vendo se o lookahead é D ou F. 14
  • 15. A PROGRAMAR BYAC C s : x D %nonassoc IFX | y F %token ELSE ; x : A B; ... y : A B; %% A existência de conflictos na gramática não impede o parser de ser gerado, já que o byacc ... tem comportamentos default quando não sabe que produção usar, mas claro que o stmt : IF expression stmt %prec IFX comportamento default pode não ser o que o | IF expression stmt ELSE stmt programador tinha em mente quando escreveu a ; gramática portanto convém eliminar os conflictos antes de gerar o parser. ... %% Os conflictos são introduzidos na escrita da gramática e podem sempre ser eliminados reescrevendo-a, mas por vezes é preferível Introduzimos o token IFX - o token ELSE já tem eliminá-los usando precedências. Tomemos o de estar definido, tal como o IF se o estamos a seguinte exemplo clássico, o “dangling else”: usar na gramática - que não é retornado pelo scanner. O IFX só existe dentro do parser e stmt : IF expression stmt serve apenas para indicar o nível de | IF expression stmt ELSE stmt precedência de uma produção. Indicamos ao ; byacc o nível de precedência dos tokens pela ordem em que os declaramos, tendo os últimos Para o seguinte input: maior precedência que os primeiros. A precedência de um token determina a if(a) precedência da produção em que ele se if(b) c = a + b; else c = a; encontra, numa situação em que duas produções são viáveis como no exemplo anterior O problema que nos surge é que o parser não a produção com maior precedência é usada. Se sabe se o que ele tem é um IF expression stmt quisermos modificar a precedência de uma com expression igual a (a) e o stmt igual a if(b) c produção sem afectar a precedência de nenhum = a + b; else c = a; ou se em vez disso tem um dos seus tokens, podemos, como mencionado IF expression stmt ELSE stmt com expression previamente, criar um token “falso” como o IFX e também igual a (a), o primeiro stmt igual a if(b) c escrever %prec IFX no fim da produção para o = a + b; e o segundo stmt igual a c = a;. O que conseguir. Usando o token IFX no primeiro IF queremos que o parser faça? Associe o else ao estamos a dizer que aquele tipo de if tem menos primeiro if ou ao segundo? O comportamento precedência que o segundo IF,já que o token IFX que esperamos é que associe ao segundo, é declarado antes do token ELSE, portanto portanto para o conseguir vamos usar quando existem as duas hipóteses o parser precedências. escolhe sempre a segunda, o que é o comportamento que desejávamos. 15
  • 16. A PROGRAMAR BYAC C expr : expr '*' expr | expr '^' expr | NUMBER | '(' expr ')' ; ; Neste caso para o input NUMBER * NUMBER * Dizemos que os operadores binários '+' e '-' são NUMBER por exemplo, o parser não sabe se há- associativos à esquerda e têm a mesma de fazer (NUMBER * NUMBER) * NUMBER ou precedência. Os operadores '*' e '/' funcionam de NUMBER * (NUMBER * NUMBER). Para forma idêntica mas têm maior precedência. O resolver este problema precisamos de indicar a operador de potência '^' é associativo à direita e associatividade do operador binário '*' ao byacc. tem a maior precedência de todos os operadores Um operador com associatividade à esquerda binários. O UMINUS indica que uma expressão para o input NUMBER * NUMBER * NUMBER * negada tem a maior precedência e que não se NUMBER faz ((NUMBER * NUMBER) * pode negar uma negação. Os parênteses forçam NUMBER) * NUMBER, um operador com a avaliação de qualquer que seja a expressão associatividade à direita faz NUMBER * que estiver dentro deles, contornando as (NUMBER * (NUMBER * NUMBER)) para o precedências caso seja necessário. Para o input, mesmo input. A forma de indicar a -1 ^2 + 5 + 3 - 2 * 3 ^ 4 ^ 5 / -6 / 2 - 5 a nossa associatividade de um token ao byacc é gramática vai fazer (((((-1 )^2) + 5) + 3) - (((2 * (3 escrever %left ou %right em vez de %token ^ (4 ^ 5))) / (-6)) / 2)) - 5 como seria de esperar. quando o declaramos. Para declarar um operador unário não associativo (ou seja um Podemos associar acções a cada produção, operador que não se pode encadear) para serem executadas quando o parser acaba escrevemos %nonassoc em vez de %token. de processar o corpo de uma produção e o substitui pela cabeça. As acções indicam-se da Entendendo associatividade e precedências mesma forma que no scanner, e é possível usar podemos começar a compreender a gramática elementos da produção dentro delas desde que da nossa calculadora. eles tenham valores associados. Para indicar o valor da cabeça usamos $$, para os membros %token NUMBER do corpo usamos $1 , $2, … $n de acordo com a ordem em que eles aparecem. Um não terminal %left '+' '-' tem por default associado um int. Se quisermos %left '*' '/' associar um tipo diferente declaramos %right '^' %type<tipo-do-valor-associado> nome-do- %nonassoc UMINUS símbolo-não-terminal na primeira secção do ficheiro. Vejamos então o ficheiro inteiro: %% %% expr : NUMBER %{ | '-' expr %prec UMINUS #include <iostream> | expr '+' expr #include <cmath> | expr '-' expr %} | expr '*' expr | expr '/' expr 16
  • 17. A PROGRAMAR BYAC C tipos associados, %union { associatividade e double d; precedência. Concluímos a }; primeira secção com a declaração que o símbolo não %token<d> NUMBER terminal expr tem um valor %token NL associado do tipo double. Isto %left '+' '-' é essencial porque as nossas %left '*' '/' operações não estão a %right '^' receber tokens NUMBER %nonassoc UMINUS como argumentos mas sim %type<d> expr não terminais expr. O símbolo inicial da nossa gramática é %% expr_list e está definido como expr_list : expr NL { std::cout << $1 << std::endl; } uma sequência de um ou mais | expr_list expr NL { std::cout << $2 << std::endl; } não terminais expr, separados ; por mudanças de linha. Associamos a cada produção expr : NUMBER { $$ = $1; } de expr_list a acção da | '-' expr %prec UMINUS { $$ = -$2; } impressão do valor de expr. | expr '+' expr { $$ = $1+$3; } As produções com cabeça | expr '-' expr { $$ = $1-$3; } expr tem associadas as | expr '*' expr { $$ = $1*$3; } acções que realizam os | expr '/' expr { $$ = $1/$3; } cálculos, guardando os | expr '^' expr { $$ = pow($1, $3); } valores na cabeça. Na terceira | '(' expr ')' { $$ = $2; } secção temos um main que ; chama o yyparse(). %% int main() Neste momento temos um { parser e um scanner para a yyparse(); nossa calculadora, no próximo } artigo veremos como ligá-los e O ficheiro começa com os #includes de C++ que como modificar o scanner e o precisamos, seguidos da %union com o único parser em conjunto de forma a adicionar mais tipo que a nossa calculadora necessita, um funcionalidades à calculadora. double. Lemos a declaração dos tokens, com os AUTOR Escrito por João Mares Estando actualmente no terceiro ano de LEIC no IST, interssa-se preferencialmente por arquitectura de computadores e computação gráfica. 17
  • 18. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk O ADO.NET Entity Framework permite criar tenham como nome “Jorge” e que tenham como aplicações em que o acesso a dados é feito com morada a “Moita”. base em um modelo conceitual e não utilizando comandos directos à base de dados. Isto Imaginemos que o programador ou o DBA permite que o programador se abstraia (database administrator) altera o campo “nome” totalmente da base de dados (criação de para “nomecompleto”, pois quer que se registe o ligações de acesso, comandos, parâmetros, etc.) nome completo do utilizador e, desta forma, o e utilize apenas objectos durante o nome do campo fica mais coerente. Se desenvolvimento. aplicação for compilada não é detectado qualquer problema e só no momento de A versão 4.0 do Entity Framework (actual), que execução irá ocorrer um erro. Situações como está disponível na .NET Framework 4.0, tem um estas são muito frequentes e podem conjunto de novas funcionalidades e melhorias, representam vários erros na aplicação. como é o caso de suporte a POCO - Plain Old CLR Objects (permite criar classes que não Este é apenas um exemplo de como se pode herdam, nem implementam nenhuma outra beneficiar, e muito, da utilização do Entity classes ou interface), abordagem Model-First Framework, mas existem muito mais vantagens (permite criar primeiro o modelo conceptual e, como a utilização de LINQ to Entities, com base nele, criar a base de dados), suporte intellisense no momento em que se está a para o uso de funções em LINQ-to-Entities, escrever o código, código mais fácil de manter e Complex Types (criação de tipos de dados actualizar, etc, etc. complexos), Deferred Loading ou Lazy Loading (capacidade de carregar as propriedades de Neste artigo, que será uma breve introdução ao associação das entidades no momento em são Entity Framework, irá apenas mostrar como chamadas, se forem chamadas), etc. Não é construir um modelo relacional de uma base de especifica apenas para o SQL Server, pois dados SQL, uma abordagem database-first, e existem providers que permitem usar outras como executar algumas operações CRUD. bases de dados, como Oracle, MySql, PostgreSQL, DB2, SQL Anywhere, Ingres, CRIAÇÃO DO MODELO RELACIONAL Progress, Firebird, Synergy, etc. (database-first) Existem várias vantagens na utilização de um Para criação de um modelo relacional iremos ORM (Object-relational mapping), que tornam a usar a seguinte base de dados SQL: sua adopção quase inevitável, mas vejamos o seguinte exemplo: “SELECT * FROM utilizadores WHERE nome = ‘Jorge’ AND morada = ‘Moita’” Este exemplo irá listar todos os utilizadores que 18
  • 19. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk Para o nome da ligação, e para este exemplo, Como é possível ver nesta imagem, existem utilize “vendasEntities“. apenas 3 tabelas, com as respectivas chaves primárias/estrangeiras: produtos, clientes e uma A última opção deste Wizard é onde são terceira tabela onde se registam os movimentos. seleccionados os objectos a utilizar no modelo. Neste exemplo são escolhidas as três tabelas já O primeiro passo é adicionar um novo item ao referidas. projecto (menu Project – Add New Item), e seleccionar no grupo de templates “Data” o item “ADO.NET Entity Data Model”. Isto irá iniciar um Wizard que permitirá criar o modelo final. De seguida seleccionar “Generate from database” e carregar em “Next”. Após este processo está criado o ficheiro EDMX, A próxima opção permite fazer a ligação à base que não é mais do que um conjunto de classes e de dados, escolhendo uma já existente ou métodos que nos permitirá aceder à base de criando uma nova ligação. dados de uma forma simples, como iremos ver de seguida. OPERAÇÕES CRUD As operações CRUD (acrónimo de Create, Read, Update e Delete em Inglês) são quatro operações básicas e fundamentais para a manipulação de bases de dados. São por isso 19
  • 20. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk bastante importantes e requerem, sem a utilização de um ORM como o Entity Framework, context.clientes.AddObject(cliente) algum trabalho que é normalmente complexo. context.SaveChanges() Com o Entity Framework este trabalho está ' Podemos verificar logo o número bastante simplificado para o programador, ' (ID) do registo inserido necessitando apenas de algumas linhas de Debug.WriteLine("Número de registo: " & código, com recurso a IntelliSense, para as cliente.id.ToString()) executar. End Using O funcionamento para todas as operações é semelhante: é criada uma nova instância da nossa entidade (neste exemplo “vendasEntities”) Apagar registos que herda de uma classe da EntityFramework chamada ObjectContext, que a classe primária e Para apagar um registo é necessário seleccionar responsável de gerir a informação como o registo correcto, neste caso usando uma objectos e a ligação dos objectos aos dados. Lambda Expression, e caso o resultado seja válido, executamos o método DeleteObject(), Inserir registos indicando o registo a apagar. Para inserir novos registos, neste caso um novo Finalmente gravamos as alterações na base de cliente, criamos uma nova instância da dados. respectiva classe, definindo as suas propriedades, que correspondem aos respectivos campos. Depois adicionamos o objecto através do método AddObject() e, Using context As New vendasEntities finalmente, executamos o método SaveChanges() que irá efectuar as respectivas ' Procura o registo com o número de alterações, neste caso inserir um registo, na ' cliente (ID) igual a 1 base de dados. Dim cliente = context.clientes.Where( Function(c) c.id = 1). FirstOrDefault() Using context As New vendasEntities If cliente IsNot Nothing Then context.clientes.DeleteObject(cliente) ' Cria um novo cliente context.SaveChanges() Dim cliente As New clientes With Else { MessageBox.Show( .nome = "Rui Paulo", "Número de cliente inválido") .morada = "Lisboa", End If .datanascimento = New DateTime(1980, 10, 31) End Using } 20
  • 21. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk Modificar Registos Using context As New vendasEntities Para modificar um registo, e à semelhança da Dim listaClientes = operação anterior, é necessário seleccionar o From c In context.clientes registo. Neste exemplo utilizamos LINQ to Where c.morada.Contains("Lisboa") And Entities para fazer essa selecção. Depois, c.datanascimento < modificamos o que for para modificar e New DateTime(1985, 1, 1) finalmente gravamos as alterações. Select c Using context As New vendasEntities For Each c As clientes In listaClientes Debug.WriteLine(c.nome) Dim cliente = Next (From c In context.clientes Where c.id = 1 End Using Select c).FirstOrDefault() Entre entidades existir normalmente If cliente IsNot Nothing Then associações, e essas associações (também With cliente representadas na última imagem), têm algo que .nome = "Rui Paulo" se designa por Navigation Properties. As .morada = "Setúbal" Navigation Properties permitem uma navegação .datanascimento = bidireccional entre entidades, de acordo com as New DateTime(1979, 10, 31) suas associações. Isto é algo bastante prático End With pois permite-nos criar queries entre várias context.SaveChanges() entidades usando LINQ to Entities. Else MessageBox.Show( O seguinte exemplo mostra esta abordagem, "Número de cliente inválido") definindo depois o resultado como DataSource End If num controlo DataGridView. End Using NOTA: Se utilizar uma base de dados anexa ao Using context As New vendasEntities Listar Registos Dim listaClientes = From c In context.clientes A listagem de registo é também muito Join m In context.movimentos semelhante às operações anteriores. Neste On m.clienteid Equals c.id exemplo, usando LINQ to Entities, vamos Join p In context.produtos seleccionar todos os registo com base num On m.produtoid Equals p.id critério, para uma variável do tipo IQueryable(Of Select m.datavenda, T), e depois efectuamos um ciclo para mostrar os resultados obtidos. 21
  • 22. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk Select m.datavenda, especiais), etc c.nome, p.produto, Estas são apenas algumas, das muitas m.preco vantagens, que nos devem fazer de uma vez por todas, deixar de usar SqlCommands, Me.DataGridView1.DataSource = listaClientes SqlConnections, DataSets, etc. End Using projecto (AttachDb), a base de dados é copiada para as pastas Debug/Release. Pode Alguns recursos interessantes: seleccionar no menu Project a opção Show All Files e verificar as alterações nessa localização. Data Developer Center http://msdn.microsoft.com/en-us/data/ef.aspx CONCLUSÃO Data Access Hands-on Labs http://msdn.microsoft.com/en- Como foi possível ver ao longo do artigo, que us/data/gg427655.aspx abordou de uma forma muito superficial algumas das funcionalidades deste ORM, o Entity ADO.NET team blog Framework é uma excelente opção para se http://blogs.msdn.com/b/adonet/ trabalhar com bases de dados. Julie Lerman's Blog É simples de utilizar, permite-nos trabalhar http://thedatafarm.com/blog/ apenas com objectos e com intellisense, resolve inúmeros problemas que são habituais quando trabalhamos directamente com a base de dados (formatos de datas, números, caracteres AUTOR Escrito por Jorge Paulino Exerce funções de analista-programador numa multinacional sediada em Portugal. É formador e ministra cursos de formação em tecnologias Microsoft .NET e VBA. É Microsoft Most Valuable Professional (MVP), em Visual Basic, pela sua participação nas comunidades técnicas . É administrador da Comunidade Portugal-a-Programar e membro de várias comunidades (PontoNetPT, NetPonto, MSDN, Experts- Exchange, CodeProject, etc). É autor do blog http://vbtuga.blogspot.com - twitter @vbtuga 22
  • 23. A PROGRAMAR Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I ) Começo com este artigo uma série de artigos sobre PF por exemplo). Como já há vários relacionados com a Programação Funcional em artigos sobre PF em diversas linguagens, como Perl. Python, Scheme, Haskell (recomendo que os leiam), deixo aqui a sugestão a alguém, para Nesta série de artigos pretendo demonstrar redigir um artigo teórico e agnóstico (em relação algumas das capacidades do Perl para utilização a linguagens de programação) sobre com o paradigma de Programação Funcional. Programação Funcional. Não pretendo ensinar nem as bases da Umas das principais Programação Funcional, nem do Perl. Vou abrir características do Perl excepções quando se tratarem de aspectos mais avançados e/ou muito relacionados com a (...) é não obrigar o própria Programação Funcional. A compreensão programador a utilizar (...) elementar do Perl e da Programação Funcional mas sim permitir ao é um requisito para a compreensão destes artigos contudo tudo será explicado de forma a programador utilizar o que permitir que um principiante possa compreender quiser quando quiser tudo e quem tiver dúvidas poderá contactar-me para as esclarecer. Algumas das funcionalidades elementares das linguagens funcionais são as funções anónimas Umas das principais características do Perl, em e as closures. O Perl tem ambas as features. seguimento do mantra da sua comunidade («There's more than one way to do it»), é não Uma das alterações que o Perl 5.1 2 trouxe foi obrigar o programador a utilizar, ou escolher um uma função chamada say. O say é basicamente paradigma de programação, mas sim permitir ao um print que adiciona um newline à string que programador utilizar o que quiser quando quiser, queremos imprimir (poupa-nos pelo menos 4 ficando ao cuidado dele ter os cuidados caracteres). necessários para que o código seja útil e siga boas práticas de programação. Há quem Qualquer uma das seguintes linhas de código concorde com esta filosofia, há quem não vai imprimir isolado numa linha a string: «Hello concorde, mas a filosofia do Perl e da sua world!»: comunidade não é o âmbito deste artigo. print "Hello world!n"; Um dos muitos paradigmas de programação que print "Hello world!"."n"; são possíveis utilizar em Perl é a Programação print "Hello world!", "n"; Funcional (PF). Contudo não cabe a este artigo say "Hello world!"; explicar a PF. Por isso sugiro que antes de prosseguirem na leitura deste artigo leiam pelo menos uma curta explicação do que é PF (os primeiros parágrafos do artigo da Wikipedia 23
  • 24. A PROGRAMAR Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I ) Para demonstrar a utilização de funções utilização nas "dispach tables": anónimas decidi criar uma implementação da função say que permite definir antes da sua my %lingua = ( #dispach table utilização como queremos que a string seja "pt" => sub { return "Olá mundo!" }, formatada: "es" => sub { return "Hola mundo!" }, "en" => sub { return "Hello world!" }, sub say { #definição da função say "fr" => sub { return "Bonjour monde!" }, my ($string, $format) = @_; ); my $str = $format->($string); print $str; sub dispach { } my $l = shift; my $format = sub { #função anónima de if(defined $lingua{$l} && exists formatação da string $lingua{$l}) { my $str = shift; my $str = $lingua{$l}->(); return $str."n"; print $str."n"; }; } say("Hello world!", $format); else { print "Erro: lingua desconhecida!n"; } Explicação do código do exemplo anterior: } dispach("fr"); Primeiro começamos por definir a função say, como definiríamos qualquer outra função em Perl. Depois definimos a função anónima de formatação, e atribuímos essa função a uma variável (que guarda uma referência para Explicação do código do exemplo anterior: código) para que possa ser passada de forma visualmente mais limpa à função say Começou por ser definido uma hash table que, (poderíamos também ter definido a função como chaves contém, as opções válidas de anónima, na invocação de say mas faria com línguas que queremos utilizar na impressão de que o código fosse muito menos legível). uma saudação e como valores, tem funções anónimas que imprimem uma saudação na língua representada pela sua chave na hash Qual a utilidade das funções anónimas? table. As utilidades são diversas. E vão desde a Isto poderia ter sido feito definindo utilização das funções anónimas para poder individualmente funções "regulares", criando modificar o comportamento de uma função que variáveis que eram referências para cada uma tenha sido criada para poder permitir essa dessas funções e utilizando essas variáveis alteração. Há quem utilize isto para poder por como valores a utilizar na hash table. exemplo poder voltar a correr código que tinha sido serializado. E passam pela utilização em Mas isso traria imediatamente dois problemas: "dispach tables". Uma outra utilidade é a aumentaria a quantidade de código necessário e este artigo tem um limite de caracteres; não 24
  • 25. A PROGRAMAR Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I ) utilizaria funções anónimas, que é o objectivo solução escale para mais opções de línguas, deste exemplo ;). sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções na Para além de isso, o que é pretendido neste programação: conter/isolar os problemas de exemplo, é algo tremendamente simples que forma a simplificar a sua resolução, facilitar a pode perfeitamente ser feito utilizando funções compreensão do código. anónimas, sem se aumentar a dificuldade relevante da sua compreensão como um todo e em parte. No próximo, artigo vou falar da segunda das principais capacidades do Perl para a Programação Funcional de que falei antes, as A opção por esta solução, em vez de a utilização closures. de um encadeamento maior de if-elsif, ou de um switch-case (também maior) permite que a (...) permite que a solução escale para mais opções de línguas, sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções na programação (...) AUTOR Escrito por Diogo Constantino é Consultor na área as tecnologias licenciadas como Software Livre, com aproximadamente vários anos de experiência profissional, especializado em desenvolvimento com Perl. Larga experiência na área de sistemas, engenharia e de operações de redes de telecoms, tendo desenvolvido, mantido e utilizado ferramentas para diversas telecoms nestas áreas. Conhecimentos em tecnologias como Perl, Python, PHP, MySQL, GNU/Linux, C, HTML, CSS, Javascript, GNU/Linux. Tendo tido ainda contacto profissional com tecnologias como Switchs, equipamentos de routing, firewalling e switching de diversos fabricantes, diversos sistemas *nix e diversas outras ferramentas e tecnologias comuns em sistemas *nix e/ou utilizadas em empresas de telecomunicações, redes e web. Relativamente conhecido advogado da causa do Software Livre em diversas comunidades. Sócio da Associação Nacional para o Software Livre e da Associação Portuguesa de Programadores de Perl. 25
  • 26. COMUNIDADE NETPONTO B a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF) Neste artigo pretendo mostrar o que é o System.ComponentModel. Esta classe permite- BackgroundWorker e vou exemplificar como se nos ajudar a gerir uma tarefa numa thread deve proceder à sua implementação usando a separada da thread principal sem termos de nos tecnologia WPF na versão .Net Framework 4. preocupar com a inicialização e gestão da thread onde vamos executar a tarefa. Suponhamos: As propriedades a ter em conta são: “Tenho um algoritmo complexo de Optimização Combinatória que irá ter como parâmetro de CancellationPending entrada um objecto do tipo World. Classe que Permite obter se a tarefa foi cancelada. define toda a estrutura de dados da minha aplicação e no final retorna o objecto World com WorkerReportsProgress as alterações realizadas pelo algoritmo.” Permite obter e definir se o BackgroundWorker vai reportar o seu progresso da tarefa. Esta geração vai implicar que tenhamos pelo menos três passos: WorkerSupportsCancellation 1 . A partir do objecto World vamos criar a Permitir obter e definir se o BackgroundWorker estrutura de dados do algoritmo; vai permitir cancelar a tarefa. 2. Gera-se o algoritmo a partir dos dados recebidos; Os métodos a ter em conta são: 3. Depois de gerar o algoritmo é preciso converter o resultado de forma a reflectir no RunWorkerAsync World o resultado do algoritmo; Permite iniciar a tarefa. Existem duas assinaturas deste método. Uma Enquanto estes três passos estão a decorrer, eu delas não tem argumento, a outra que o tem quero ser informada sobre o progresso da utiliza-o na execução da tarefa. geração do algoritmo e pretendo ter a capacidade de a cancelar. CancelAsync Permite cancelar a tarefa e consequentemente o Este cenário é um dos muitos cenários onde o BackgroundWorker irá terminar. BackgroundWorker pode ser implementado. Para que seja possível cancelar a tarefa é Outros exemplos reais são a leitura de ficheiros necessário que a propriedade extensos, aceder a base de dados para efectuar WorkerSupportsCancellation tenha o valor de o carregamento de dados, fazer o load de verdade true. imagens e gerar relatórios. ReportProgress Antes de passarmos à implementação vou dar Permite reportar o progresso da tarefa em dado uma breve apresentação teórica: momento. Para que o progresso seja reportado é Um BackgroundWorker é uma classe contida no necessário que o WorkerReportsProgress tenha 26