tag:blogger.com,1999:blog-18760869564783354622024-02-20T23:45:18.700+00:00Cheap CodeLuís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-1876086956478335462.post-68853110911913364652013-02-13T23:48:00.000+00:002013-02-15T09:48:26.671+00:00QuickSort funcional com C# – Uma só linha de código<p>No processo de aprendizagem de linguagens funcionais por vezes ficamos abismados com a simplicidade com que são abordados alguns algoritmos que tipicamente damos como complexos. Aqui há uns dias estava a resolver uns exercícios de <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)" target="_blank"><em><span style="color: #99aadd">Lisp</span></em></a> quando dei por mim a observar a implementação de um <em><a href="http://pt.wikipedia.org/wiki/Quicksort" target="_blank"><span style="color: #99aadd">QuickSort</span></a></em> nesta linguagem: <br /> <br /><span style="font-family: consolas"><strong>(defun partition (fun array) <br />  (list (remove-if-not fun array) (remove-if fun array))) <br />(defun sort (array) <br />  (if (null array) nil <br />    (let ((part (partition (lambda (x) (< x (car array))) (cdr array)))) <br />      (append (sort (car part)) (cons (car array) (sort (cadr part)))))))</strong></span> <br /><em>(retirado do artigo na <a href="http://pt.wikipedia.org/wiki/Quicksort#Lisp" target="_blank"><span style="color: #99aadd">wikipedia</span></a>)</em> <br /> <br />Assim de repente isto tem um aspecto bem mais simples do que as implementações comuns em C#, Java ou qualquer outra linguagem orientada a objectos. No fundo, o conceito do algoritmo diz para escolher um elemento e juntar a lista ordenada de todos os menores com o elemento e com a lista ordenada de todos os maiores. Simples, não? Então e porque não fazer o mesmo em C#? É possível implementar um <em><a href="http://pt.wikipedia.org/wiki/Quicksort" target="_blank"><span style="color: #99aadd">QuickSort</span></a> </em>apenas com uma linha de código? Uma primeira tentativa: <br /> <br /><span style="font-family: consolas"><strong><span style="color: #f3f3f3"><span style="color: #a2c4fd">public</span> <span style="color: #a2c4fd">static</span> <span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span> LinqIntQuickSort(<span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span> x) <br />{ <br />    <span style="color: #a2c4fd">return</span> x<span style="color: #fffdaa">.</span>Count() <span style="color: #fffdaa"><=</span> 1 <br />        <span style="color: #fffdaa">?</span> x <br />        : LinqIntQuickSort(x<span style="color: #fffdaa">.</span>Skip(1)<span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> z <span style="color: #fffdaa"><=</span> x<span style="color: #fffdaa">.</span>First())) <br />            <span style="color: #fffdaa">.</span>Concat(<span style="color: #a2c4fd">new</span> <span style="color: #fcf38b">List</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span> { x<span style="color: #fffdaa">.</span>First() }) <br />            <span style="color: #fffdaa">.</span>Concat(LinqIntQuickSort(x<span style="color: #fffdaa">.</span>Skip(1)<span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> z <span style="color: #fffdaa">></span> x<span style="color: #fffdaa">.</span>First()))); <br />}</span></strong></span></p> <p>E não é que funciona? Ok, mas apenas com números. Generalizando obtemos algo do género:</p> <p> <span style="font-family: consolas"><strong><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"><font size="2"><span style="color: #a2c4fd">public</span> <span style="color: #a2c4fd">static</span> <span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span>T<span style="color: #fffdaa">></span> LinqGenericQuickSort<span style="color: #fffdaa"><</span>T<span style="color: #fffdaa">></span>(<span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span>T<span style="color: #fffdaa">></span> x, <span style="color: #fd9f42">Func</span><span style="color: #fffdaa"><</span>T, T, <span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span> fnCompare) <br />{ <br />    <span style="color: #a2c4fd">return</span> x<span style="color: #fffdaa">.</span>Count() <span style="color: #fffdaa"><=</span> 1 <br />        <span style="color: #fffdaa">?</span> x <br />        : LinqGenericQuickSort(x<span style="color: #fffdaa">.</span>Skip(1) <br />                <span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> fnCompare(z, x<span style="color: #fffdaa">.</span>First()) <span style="color: #fffdaa"><=</span> 0), fnCompare) <br />            <span style="color: #fffdaa">.</span>Concat(<span style="color: #a2c4fd">new</span> <span style="color: #fcf38b">List</span><span style="color: #fffdaa"><</span>T<span style="color: #fffdaa">></span> { x<span style="color: #fffdaa">.</span>First() }) <br />            <span style="color: #fffdaa">.</span>Concat(LinqGenericQuickSort(x<span style="color: #fffdaa">.</span>Skip(1) <br />                <span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> fnCompare(z, x<span style="color: #fffdaa">.</span>First()) <span style="color: #fffdaa">></span> 0), fnCompare)); <br />}</font></span></span></span></strong></span></p> <p><span style="font-family: consolas"><strong><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"></span></span></span></strong></span><span style="font-family: trebuchet ms"><font size="2">Que, para a mesma lista de inteiros, pode ser chamado simplesmente assim:</font></span></p> <p><span style="font-family: consolas"><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"><font size="2"><strong>sortedList <span style="color: #fffdaa">=</span> LinqGenericQuickSort(unsortedList, (x, y) <span style="color: #fffdaa">=></span> x <span style="color: #fffdaa">-</span> y);</strong></font></span></span></span></span></p> <p><span style="font-family: consolas"><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"></span></span></span></span><span style="font-family: trebuchet ms"><font size="2">Já agora, se quisermos apenas utilizar uma <a href="http://msdn.microsoft.com/en-us/library/bb397687.aspx" target="_blank"><span style="color: #99aadd"><em>expressão lambda</em></span></a>:</font></span></p> <p><span style="font-family: consolas"><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"><font size="2"><strong><span style="color: #fd9f42">Func</span><span style="color: #fffdaa"><</span><span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span>, <span style="color: #fd9f42">Func</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span>, <span style="color: #a2c4fd">int</span>, <span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span>, <span style="color: #2b91af">IEnumerable</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">>></span> fn <span style="color: #fffdaa">=</span> <span style="color: #a2c4fd">null</span>; <br />fn <span style="color: #fffdaa">=</span> (l1, fnCompare) <span style="color: #fffdaa">=></span> l1<span style="color: #fffdaa">.</span>Count() <span style="color: #fffdaa"><=</span> 1 <br />    <span style="color: #fffdaa">?</span> l1 <br />    : fn(l1<span style="color: #fffdaa">.</span>Skip(1)<span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> fnCompare(z, l1<span style="color: #fffdaa">.</span>First()) <span style="color: #fffdaa"><=</span> 0), fnCompare) <br />        <span style="color: #fffdaa">.</span>Concat(<span style="color: #a2c4fd">new</span> <span style="color: #fcf38b">List</span><span style="color: #fffdaa"><</span><span style="color: #a2c4fd">int</span><span style="color: #fffdaa">></span> { l1<span style="color: #fffdaa">.</span>First() }) <br />        <span style="color: #fffdaa">.</span>Concat(fn(l1<span style="color: #fffdaa">.</span>Skip(1)<span style="color: #fffdaa">.</span>Where(z <span style="color: #fffdaa">=></span> fnCompare(z, l1<span style="color: #fffdaa">.</span>First()) <span style="color: #fffdaa">></span> 0), fnCompare)); <br /> <br /><span style="font-family: consolas"><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"><font size="2"><strong>sortedList <span style="color: #fffdaa">=</span> </strong></font></span></span></span></span>fn(list, (x, y) <span style="color: #fffdaa">=></span> x <span style="color: #fffdaa">-</span> y);</strong></font></span></span></span></span></p> <p><span style="font-family: consolas"><span style="color: #f3f3f3"><span style="font-size: x-small"><span style="font-size: x-small"></span></span></span></span><span style="font-family: trebuchet ms"><font size="2">Atenção que este exemplo apenas serve para demonstrar potencialidades do <em><a href="http://msdn.microsoft.com/en-us/library/bb397933.aspx" target="_blank"><span style="color: #99aadd">Linq</span></a></em> e </font></span><a href="http://msdn.microsoft.com/en-us/library/bb397687.aspx" target="_blank"><em><span style="color: #99aadd"><span style="font-family: trebuchet ms"><font size="2">expressões lambda</font></span></span></em></a><span style="font-family: trebuchet ms"><font size="2">, é muito ineficiente quando comparado com as implementações tradicionais.</font></span></p> Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-85473813732668918452011-08-18T15:05:00.001+01:002011-08-19T18:17:55.191+01:00Enumeração de listas com Tasks<span xmlns=''><p>Imaginemos que num código já existente temos um método que itera uma lista e que efectua uma qualquer operação com o seu conteúdo. Neste exemplo simplesmente imprime o próprio item:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas; font-size:8pt'><strong> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> AsyncPrint<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fcf38b'>List<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#a2c4fd'>foreach<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> i <span style='color:#a2c4fd'>in<span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#fcf38b'>Console<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>WriteLine(<span style='color:#6afd51'>"-> :{0}"<span style='color:#f3f3f3'>, i);<br/> }<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Então alguém decide que a operação que é efectuada sobre cada item pode ser feita em paralelo e nem sequer é necessário aguardar pelo resultado. O código é alterado para:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas; font-size:8pt'><strong> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> AsyncPrint1<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fcf38b'>List<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#a2c4fd'>foreach<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> i <span style='color:#a2c4fd'>in<span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#fcf38b'>Task<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Factory<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>StartNew(() <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> { <span style='color:#fcf38b'>Console<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>WriteLine(<span style='color:#6afd51'>"-> :{0}"<span style='color:#f3f3f3'>, i); });<br/> }<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>A questão que se coloca é: <span style='color:#ffc000'><strong>o resultado é o mesmo?</strong><br/></span>Ou melhor ainda se o programador que altera este código é fã de <a href='http://msdn.microsoft.com/en-us/library/bb397687.aspx'><span style='color:blue; text-decoration:underline'><em>lambda expressions</em></span></a> e reescreve desta forma:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas; font-size:8pt'><strong> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> AsyncPrint2<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fcf38b'>List<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> list)<br/> {<br/> list<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>ForEach((i) <span style='color:#fffdaa'>=><span style='color:#f3f3f3'><br/> {<br/> <span style='color:#fcf38b'>Task<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Factory<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>StartNew(() <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> { <span style='color:#fcf38b'>Console<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>WriteLine(<span style='color:#6afd51'>"-> :{0}"<span style='color:#f3f3f3'>, i); });<br/> });<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>O output dos métodos <em>AsyncPrint</em>, <em>AsyncPrint1</em> e <em>AsyncPrint2</em> é semelhante? Não é? Como é possível? O que está a acontecer?<br/>Ora, o método <em>AsyncPrint2</em> obtém o mesmo resultado do <em>AsyncPrint</em>, mas em <em>AsyncPrint1</em> obtemos um resultado diferente. Tipicamente, é impresso sempre o mesmo item ou alguns são impressos em duplicado e faltam outros. Porquê? Ao iniciar uma <a href='http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx'><span style='color:blue; text-decoration:underline'><em>Task</em></span></a> dentro da enumeração tradicional do <em>foreach</em> e como a acção concreta está definida num <a href='http://msdn.microsoft.com/en-us/library/900fyy8e(v=VS.100).aspx'><span style='color:blue; text-decoration:underline'><em>delegate</em></span></a> (ou <em>lambda expression</em>) contido no método, a variável <em>i</em> que é acedida no corpo do <em>delegate</em> é uma <a href='http://en.wikipedia.org/wiki/Closure_(computer_science)'><span style='color:blue; text-decoration:underline'><em>closure</em></span></a> que revela o seu valor no momento que é acedida. Quando a lista é iterada, é dada ordem de início de uma tarefa para o tratamento do item actual e avança-se para o próximo, mas a iteração da lista continua enquanto a <a href='http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx'><span style='color:blue; text-decoration:underline'><em>Thread</em></span></a> se mantiver em execução. Ou seja, não é garantido que a tarefa se inicie no momento da sua criação e muito provavelmente, quando esta se iniciar, a enumeração já avançou e o item actual já não é o mesmo.<br/>No método <em>AsyncPrint2</em> o comportamento é o esperado porque a variável <em>i</em> é um parâmetro de entrada do <em>delegate</em> que é invocado na implementação do método <a href='http://msdn.microsoft.com/en-us/library/bwabdf9z.aspx'><span style='color:blue; text-decoration:underline'><em>List<T>.forEach()</em></span></a>, não é uma <em>closure</em>.<br/>Então, como se pode fazer para manter a utilização da expressão clássica do <em>foreach</em>? Simples, basta que se deixe de utilizar a variável de iteração como <em>closure</em>:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas; font-size:8pt'><strong> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> AsyncPrint3<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fcf38b'>List<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#a2c4fd'>foreach<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> i <span style='color:#a2c4fd'>in<span style='color:#f3f3f3'> list)<br/> {<br/> <span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> x <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> i;<br/> <span style='color:#fcf38b'>Task<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Factory<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>StartNew(() <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> { <span style='color:#fcf38b'>Console<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>WriteLine(<span style='color:#6afd51'>"-> :{0}"<span style='color:#f3f3f3'>, x); });<br/> }<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Já agora, também se pode utilizar a <a href='http://msdn.microsoft.com/en-us/library/dd460717.aspx'><span style='color:blue; text-decoration:underline'><em>Task Parallel Library</em></span></a>, assim:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas; font-size:8pt'><strong> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> AsyncPrint4<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fcf38b'>List<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> list)<br/> {<br/> list<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>AsParallel()<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>ForAll((i) <span style='color:#fffdaa'>=><span style='color:#f3f3f3'><br/> {<br/> <span style='color:#fcf38b'>Console<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>WriteLine(<span style='color:#6afd51'>"-> :{0}"<span style='color:#f3f3f3'>, i); <br/> });<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>No entanto, é necessário ter em atenção que aqui o comportamento será ligeiramente diferente: neste caso o método só termina quando a operação terminar em todos os itens da lista enquanto que nos exemplos anteriores isso não acontece.<br /></p><p>Para aprender mais sobre <em>closures</em> recomendo este artigo do Jon Skeet: <a href='http://csharpindepth.com/Articles/Chapter5/Closures.aspx'><span style='color:blue; text-decoration:underline'><em>The Beauty of Closures</em></span></a></p></span>Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-63253060802146563752011-05-01T16:31:00.002+01:002011-08-18T14:10:06.160+01:00Acesso ao contexto em linha<span xmlns=''><p>Para quem utiliza Entity Framework, o acesso aos dados é fornecido pelo contexto (gerado pelo Entity Data Model Designer). Ora, o contexto gerado pela ferramenta deriva de System.Data.Objects.ObjectContext que por sua vez implementa IDisposable. Dizem as boas práticas que um objecto que seja IDisposable deve ser usado da seguinte forma:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas'><strong> <span style='color:#a2c4fd'>public<span style='color:#f3f3f3'> <span style='color:#2b91af'>IEnumerable<span style='color:#fffdaa'><<span style='color:#fcf38b'>Product<span style='color:#fffdaa'>><span style='color:#f3f3f3'> Products { <span style='color:#a2c4fd'>get<span style='color:#f3f3f3'>; <span style='color:#a2c4fd'>set<span style='color:#f3f3f3'>; }<br/> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> Sample1()<br/> {<br/> <span style='color:#a2c4fd'>using<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> ctx <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>new<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#f3f3f3'>())<br/> {<br/> Products <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> ctx<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Products<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Where(p <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> p<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>UnitPrice <span style='color:#fffdaa'><<span style='color:#f3f3f3'> 10);<br/> }<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Simples e eficaz. Mas, agora imaginemos que quero carregar a lista de produtos num outro objecto e até a posso colocar no construtor ou na inicialização directa:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas'><strong> <span style='color:#a2c4fd'>class<span style='color:#f3f3f3'> <span style='color:#fcf38b'>SomeObject<span style='color:#f3f3f3'> { <span style='color:#a2c4fd'>public<span style='color:#f3f3f3'> <span style='color:#2b91af'>IEnumerable<span style='color:#fffdaa'><<span style='color:#fcf38b'>Product<span style='color:#fffdaa'>><span style='color:#f3f3f3'> Products { <span style='color:#a2c4fd'>get<span style='color:#f3f3f3'>; <span style='color:#a2c4fd'>set<span style='color:#f3f3f3'>; } }<br/><br/> <br/> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> Sample2()<br/> {<br/> <span style='color:#a2c4fd'>using<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> ctx <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>new<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#f3f3f3'>())<br/> {<br/> <span style='color:#fcf38b'>SomeObject<span style='color:#f3f3f3'> someObject1 <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>new<span style='color:#f3f3f3'> <span style='color:#fcf38b'>SomeObject<span style='color:#f3f3f3'>()<br/> {<br/> Products <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> ctx<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Products<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Where(p <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> p<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>UnitPrice <span style='color:#fffdaa'><<span style='color:#f3f3f3'> 10)<br/> };<br/> }<br/> <span style='color:#00a636'>//someObject1 not available here...<span style='color:#f3f3f3'><br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Então temos um problema: é que a utilização do objecto criado fica restrita ao corpo da estrutura using. É certo que se pode declarar o objecto fora da estrutura ou simplesmente expandir a estrutura, mas isso nem sempre é desejável. Para contornar esta situação costumo utilizar um pequeno método inspirado na inversão de controlo, assim:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas'><strong> <span style='color:#a2c4fd'>public<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>partial<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>class<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#f3f3f3'><br/> {<br/> <span style='color:#a2c4fd'>public<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>static<span style='color:#f3f3f3'> T Execute<span style='color:#fffdaa'><<span style='color:#f3f3f3'>T<span style='color:#fffdaa'>><span style='color:#f3f3f3'>(<span style='color:#fd9f42'>Func<span style='color:#fffdaa'><<span style='color:#fcf38b'>NorthwindEntities<span style='color:#f3f3f3'>, T<span style='color:#fffdaa'>><span style='color:#f3f3f3'> f)<br/> {<br/> <span style='color:#a2c4fd'>using<span style='color:#f3f3f3'> (<span style='color:#a2c4fd'>var<span style='color:#f3f3f3'> ctx <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>new<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#f3f3f3'>())<br/> {<br/> <span style='color:#a2c4fd'>return<span style='color:#f3f3f3'> f(ctx);<br/> }<br/> }<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Neste caso, coloquei o método na própria classe de contexto, mas pode ser colocado numa qualquer classe estática. A razão de o ter colocado directamente no contexto é que é dependente do próprio contexto devido à inicialização local do mesmo. Com esta pequena ajuda, a mesma consulta pode ser escrita assim:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas'><strong> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> Sample3()<br/> {<br/> Products <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Execute(ctx <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> ctx<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Products<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Where(p <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> p<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>UnitPrice <span style='color:#fffdaa'><<span style='color:#f3f3f3'> 10));<br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Ou assim:<br /></p><p><pre><code><span style='color:#f3f3f3'><span style='font-family:Consolas'><strong> <span style='color:#a2c4fd'>void<span style='color:#f3f3f3'> Sample4()<br/> {<br/> <span style='color:#fcf38b'>SomeObject<span style='color:#f3f3f3'> someObject1 <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#a2c4fd'>new<span style='color:#f3f3f3'> <span style='color:#fcf38b'>SomeObject<span style='color:#f3f3f3'>()<br/> {<br/> Products <span style='color:#fffdaa'>=<span style='color:#f3f3f3'> <span style='color:#fcf38b'>NorthwindEntities<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Execute(ctx <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> ctx<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Products<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>Where(p <span style='color:#fffdaa'>=><span style='color:#f3f3f3'> p<span style='color:#fffdaa'>.<span style='color:#f3f3f3'>UnitPrice <span style='color:#fffdaa'><<span style='color:#f3f3f3'> 10))<br/> };<br/> <span style='color:#00a636'>//someObject1 available here...<span style='color:#f3f3f3'><br/> }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></strong></span><br /> </span></code></pre></p><p>Claro que este exemplo apenas tem utilização quando o contexto apenas é necessário para uma única consulta. Para mais do que uma consulta deverá sempre ser utilizado o padrão standard.<br /></p></span>Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-11792589936231092562010-02-03T21:03:00.000+00:002010-03-08T21:23:40.424+00:00Formação SCRUM Master<p>Nos dias 1 e 2 de estive na formação SCRUM Master com <a href="http://mitchlacey.com/" target="_blank">Mitch Lacey</a> e <a href="http://jeffsutherland.com/" target="_blank">Jeff Sutherland</a>. Na minha luta contra algumas ideias feitas oriundas das metodologias tradicionais, tinha já alguma informação sobre a forma de organização do SCRUM e já não é a primeira vez que tento seguir alguns dos fundamentos.</p> <p>A possibilidade de trocar impressões com alguém como o sr. Jeff Sutherland é algo de único. Além de ser um dos co-autores do SCRUM e um dos signatários do <a href="http://agilemanifesto.org/" target="_blank">manifesto ágil</a>, tem uma carreira impressionante que vai por exemplo desde piloto de caça na guerra do Vietnam a investigador de tratamentos contra o cancro. Vejam a página dele no <a href="http://www.linkedin.com/in/jeffsutherland" target="_blank">linkedin</a>!</p> <p>Podem também ver este <a href="http://www.youtube.com/watch?v=Ht2xcIJrAXo" target="_blank">vídeo</a>.</p> <p>O Mitch Lacey (<a href="http://www.linkedin.com/in/mitchlacey" target="_blank">linkedin</a>) é um comunicador nato com muita experiencia em aplicação de SCRUM em projectos reais.</p> <p>Foram dois dias muito intensos para depois voltar ao mundo real...</p> Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-74216298307260855072009-10-24T00:57:00.001+01:002009-10-24T01:00:05.915+01:00You can’t control what you can’t measure<p>Não consegues controlar o que não consegues medir. Forte, não é? Esta afirmação é utilizada como um dos grandes chavões em todas as exposições onde se defende a aplicação exaustiva de métricas sobre processos de desenvolvimento de software. A maioria das pessoas que "põe a mão na massa" tem o sentimento de que pouco ou nada significam essas métricas e que são normalmente fabricadas simplesmente para acolher a norma A ou B de um qualquer processo de qualidade.</p> <p>Mas voltemos ao inicio: esta frase é retirada do livro "<a href="http://www.amazon.com/Controlling-Software-Projects-Management-Measurement/dp/0131717111" target="_blank">Controling Software Projects: Management, Measurement and Estimation</a>" escrito pelo Sr<a href="http://en.wikipedia.org/wiki/Tom_DeMarco" target="_blank">. Tom DeMarco</a> em 1982. Este livro é uma referência e muitas das suas recomendações ou práticas são utilizadas em gestão de projectos de desenvolvimento de software. Então mas, e se de repente o Sr. DeMarco viesse dizer que, afinal, se calhar as coisas não são bem assim? Que a construção de software não pode ser comparada com as engenharias clássicas e que este tipo de controle exacerbado apenas serve para castrar toda e qualquer possibilidade de criar software inovador e com real valor acrescentado? UOOWWWW??!?!?</p> <p>Pois é… Aconselho vivamente a leitura do artigo que está publicado no site do <a href="http://www.computer.org" target="_blank">IEEE Computer Society</a>. O pdf pode ser descarregado <a href="http://www.computer.org/cms/Computer.org/ComputingNow/homepage/2009/0709/rW_SO_Viewpoints.pdf" target="_blank">aqui</a>.</p> <p>Este artigo tem causado alguma polémica por esse mundo fora, basta ver por exemplo a quantidade de comentários ao <a href="http://www.codinghorror.com/blog/archives/001288.html" target="_blank">este artigo</a> de Jeff Atwood no seu fantástico blog <a href="http://www.codinghorror.com" target="_blank">Coding Horror</a>.</p> Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-1444884695593521392009-02-05T19:23:00.001+00:002009-02-05T19:23:42.112+00:00DevDays 2009<p>Nos próximos dias 18 e 19 de Fevereiro no campus do Taguspark. Evento para programadores, designers, arquitectos e todos aqueles que criam soluções em plataformas Microsoft. <p>Eu vou lá estar. Quem me quiser encontrar é só procurar junto das sessões sobre .Net e C# 4.0, Windows Azure, Team System e nos tópicos de arquitectura em geral. A inscrição são 100€, valor muito em conta para um evento de dois dias com almoço e lanches incluídos e a oportunidade de escutar de perto alguns gurus da actualidade. Vai a <a target="_blank" href="http://www.devdays09.com">http://www.devdays09.com</a> e inscreve-te. Vemo-nos por lá!</p> Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-35750478244466240722008-06-03T11:31:00.001+01:002008-06-03T16:41:47.667+01:00Parallel Extensions June 2008 CTP<p>Está disponível para download <a href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567802.aspx" target="_blank">a CTP 2008 da Parallel Extensions</a>. Há já algum tempo que venho a utilizar a versão anterior de Dez07 (inclusive em algum código de produção) sem grandes problemas. Para quem não conhece, aconselho vivamente a experimentar. Esta API não nos trás nada que não fosse possível fazer antes, trás sim uma simplicidade fantástica em tirar partido de hardware multi-core.</p> <p>Penso que estamos à beira de uma grande revolução no modo de pensar e estruturar algoritmos. Tal como educámos o nosso modo de pensar de um modo sequencial e estruturado para um modo orientado a objectos, é tempo de educarmos o nosso pensamento para muti-processo. Quando desenvolvemos um algoritmo temos de pensar logo à partida nas dependências e nos blocos que são ou não dependentes e que podem ou não ser executados de modo assíncrono. Tal como disse atrás não é nada de novo mas a implementação era mais complexa e na maior parte dos casos não havia necessidade de complicar. A democratização do hardware multi-processador / multi-core e a simplicidade que nos trás esta API torna esta tecnologia acessível a um leque muito maior de situações do dia-a-dia.</p> Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-14951712187288199742008-05-17T11:36:00.001+01:002008-05-28T10:23:17.141+01:00Como iniciar uma thread com múltiplos parâmetros<span xmlns="xmlns"><p>Ainda hoje surgiu esta questão. Necessito de executar um pedaço de código numa Thread separada mas tenho de lhe passar um conjunto de parâmetros. A solução clássica passa por criar uma classe que expõe as propriedades necessárias e executar a thread numa instância dessa classe. Algo do género:</p><blockquote><p><span style="font-family:courier new;font-size:10;"><span style="color:#2b91af;">MyThreadClass</span> myThreadClass1 = <span style="color:blue;">new </span><span style="color:#2b91af;">MyThreadClass</span>() { P1 = 1, P2 = <span style="color:#a31515;">"teste"</span> };<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:#2b91af;">ThreadStart</span> threadStart1 = <span style="color:blue;">new</span> <span style="color:#2b91af;">ThreadStart</span>(myThreadClass1.start);<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:#2b91af;">Thread</span> thread1 = <span style="color:blue;">new</span> <span style="color:#2b91af;">Thread</span>(threadStart1);<br /></span><span style="font-family:courier new;font-size:10;">thread1.Start();<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">class</span> <span style="color:#2b91af;">MyThreadClass</span><br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">public</span> <span style="color:blue;">int</span> P1 { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">public</span> <span style="color:blue;">string</span> P2 { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">public</span> <span style="color:blue;">void</span> start()<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//algum código...<br /></span></span><span style="font-family:courier new;font-size:10;">}<br /></span><span style="font-family:courier new;font-size:10;">}</span><span style="font-family:courier new;font-size:10;"></span></p></blockquote><p>Pode-se também criar uma struct ou classe simples onde se colocam os parâmetros necessários e utilizar o <span style="font-family:courier new;font-size:10;color:#2b91af;">ParameterizedThreadStart</span>, mas a questão mantêm-se: se o código a executar paralelamente é algo muito simples, não deveria haver uma solução mais simples? Claro que há. O construtor da classe Thread pode receber uma <span style="font-family:courier new;font-size:10;color:#2b91af;">ThreadStart</span> ou uma <span style="font-family:courier new;font-size:10;color:#2b91af;">ParameterizedThreadStart</span>. Ambos são delegates. Porque não construir <span style="font-family:courier new;font-size:10;color:#2b91af;">ThreadStart</span> que aponte para um simples delegate que por sua vez chama o método que se pretende paralelo? Como por exemplo: </p><blockquote><p><span style="font-family:courier new;font-size:10;"><span style="color:#2b91af;">ThreadStart</span> threadStart1 = <span style="color:blue;">delegate</span> { threadWith2Parameters(<span style="color:#a31515;">"texto 1"</span>, <span style="color:#a31515;">"texto 2"</span>); };<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:#2b91af;">Thread</span> thread1 = <span style="color:blue;">new</span> <span style="color:#2b91af;">Thread</span>(threadStart1);<br /></span><span style="font-family:courier new;font-size:10;">thread1.Start();</span><br /><span style="font-family:courier new;font-size:10;"><span style="color:blue;">private</span> <span style="color:blue;">void</span> threadWith2Parameters(<span style="color:blue;">string</span> i1, <span style="color:blue;">string</span> i2)<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//algum código...<br /></span></span><span style="font-family:courier new;font-size:10;">}</span></p></blockquote><p>Assim é possível executar qualquer método que esteja incluído na mesma classe independentemente dos seus parâmetros. Compactando mais o código fica apenas: </p><blockquote><p><span style="font-family:courier new;font-size:10;">(<span style="color:blue;">new</span> <span style="color:#2b91af;">Thread</span>((<span style="color:#2b91af;">ThreadStart</span>)<span style="color:blue;">delegate</span> { threadWith2Parameters(<span style="color:#a31515;">"texto 1"</span>, <span style="color:#a31515;">"texto 2"</span>); })).Start();</span> </p></blockquote><p>Em ambientes WinForms é quase sempre preferível executar tarefas possivelmente demoradas em Thread's paralelas para evitar o congelamento da janela. Com este tipo de mecanismos evita-se que o código fique demasiado complexo. Imagine-se por exemplo um botão que executa um qualquer serviço remoto: </p><blockquote><p><span style="font-family:courier new;font-size:10;"><span style="color:blue;">private</span> <span style="color:blue;">void</span> button1_Click(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;">(<span style="color:blue;">new</span> <span style="color:#2b91af;">Thread</span>((<span style="color:#2b91af;">ThreadStart</span>)<span style="color:blue;">delegate</span> { listClients(<span style="color:#a31515;">"sousa"</span>, <span style="color:#a31515;">"lisboa"</span>); })).Start();<br /></span><span style="font-family:courier new;font-size:10;">}<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">private</span> <span style="color:blue;">void</span> listClients(<span style="color:blue;">string</span> name, <span style="color:blue;">string</span> address)<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">this</span>.BeginInvoke((<span style="color:#2b91af;">MethodInvoker</span>)<span style="color:blue;">delegate</span>()<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//método para bloquear controlos...<br /></span></span><span style="font-family:courier new;font-size:10;">});<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">try<br /></span></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//algum código...<br /></span></span><span style="font-family:courier new;font-size:10;">}<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">catch</span> (<span style="color:#2b91af;">Exception</span> ex)<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//tratar o erro...<br /></span></span><span style="font-family:courier new;font-size:10;">}<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">finally<br /></span></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:blue;">this</span>.BeginInvoke((<span style="color:#2b91af;">MethodInvoker</span>)<span style="color:blue;">delegate</span>()<br /></span><span style="font-family:courier new;font-size:10;">{<br /></span><span style="font-family:courier new;font-size:10;"><span style="color:green;">//método para desbloquear controlos...<br /></span></span><span style="font-family:courier new;font-size:10;">});<br /></span><span style="font-family:courier new;font-size:10;">}<br /></span><span style="font-family:courier new;font-size:10;">}</span> </p></blockquote><p>Existem por ai outras abordagens. Fica apenas mais uma. </p></span>Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-82770210465079429042008-05-16T00:53:00.001+01:002008-05-16T22:26:23.233+01:00Desenvolver software ou construir casas?<span xmlns=''><p>Diversas vezes que somos confrontados com esta questão:<br /></p><p> Porque razão desenvolver software não é um processo previsível e controlado como outras áreas de engenharia, como construção civil, por exemplo?<br /></p><p>A resposta comum a esta questão passa normalmente por tentativas de mecanizar, burocratizar, medir, controlar o processo de desenvolvimento. Passa por adoptar metodologias monstruosas que acrescentam ao desenvolvimento uma quantidade de processos muitas vezes supérfluos e sem qualquer valor acrescentado. Na maior parte dos casos inclusive acabamos por nos esquecer que o principal resultado, aquele pelo qual o cliente paga que é:… código a funcionar. O principal produto num projecto de desenvolvimento de um portal, por exemplo, não é uma lista de casos de uso nem diagramas de sequência nem sequer gráficos de GANT! O principal produto é o portal a FUNCIONAR!<br /></p><p>Ora o cenário comum é inundar as equipas de desenvolvimento com processos de qualidade burocráticos, numa tentativa de "controlar" e "tornar previsível" o processo de desenvolvimento. Em diversos casos que assisti até hoje, normalmente o resultado é… nenhum. O desenvolvimento é feito da mesma forma e no final do dia ou da semana (ou mesmo do projecto), os programadores vão consumir tempo e dinheiro a escrever documentação que não vai ter qualquer utilização que não seja mostrar nas auditorias.<br /></p><p>Não quero com isto dizer que a construção de uma aplicação deva ser feita sem qualquer controlo, mas sim que a documentação a criar deve ser a necessária para ajudar no desenvolvimento do produto. Consumir tempo a criar diagramas de sequencia depois do software estar desenvolvido é apenas perda de tempo. Ou é feito antes do desenvolvimento no intuito de se perceber o que se vai fazer e encontrar a melhor forma de o fazer ou é simplesmente perda de tempo. <br /></p><p>Analisando o outro lado (que conheço muito pouco), quando se desenvolve um projecto de construção, os arquitectos e engenheiros têm um determinado conhecimento sobre os materiais que vão ser utilizados, o seu comportamento, a sua utilização, a sua assemblagem. Agora pergunto: qual é o domínio de um arquitecto de software (quando existe um) ou um chefe de projecto sobre as linguagens, plataformas, componentes ou protocolos que vão ser utilizados? Já para não falar que nas engenharias tradicionais, tanto as matérias primas como produto final é quase sempre algo materializável, palpável. O desenvolvimento de software é um processo criado na totalidade sobre abstracção. Posso ter uma aplicação que tenha algumas funcionalidades, mas não deixa de ser uma abstracção, bem diferente de uma parede, uma janela ou uma casa. Quer queiramos ou não, o desenvolvimento de software é sempre muito mais complexo e dificilmente quem desenha ou planeia tem domínio suficiente sobre a sua construção para que consiga prever o resultado na sua totalidade. O arquitecto pode não saber como se coloca um parapeito numa janela, mas existe um conhecimento adquirido de que isso é possível e além do mais, os materiais são físicos e pouco mutáveis. Em último caso com mais umas pancadas e a coisa vai ao sítio. Do outro lado quando se planeia uma comunicação entre dois sistemas não existe domínio concreto sobre os problemas que vão existir em garantir a comunicação. Vão aparecer problemas de protocolos, autenticações, localização, etc… que podem ser resolvidos em muito pouco tempo ou podem gerar perdas de dias ou semanas. Tal como o arquitecto coloca uma janela algures numa parede, para quem planeia uma aplicação é simples desenhar num diagrama uma seta que significa uma comunicação entre dois sistemas, mas o conhecimento que os ambos têm sobre a implementação concreta, a complexidade ou os problemas que irão surgir a meio não é de todo comparável.<br /></p><p>Então em que ficamos? Simplesmente são processos demasiado distintos para que devam ser comparados. Quando me colocam esta questão contraponho:<br /></p><p><em>"Então as obras de engenharia civil nunca falham, nunca excedem orçamentos e estão sempre terminadas na data estipulada?"</em></p></span>Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0tag:blogger.com,1999:blog-1876086956478335462.post-75967182271685783242008-04-16T15:18:00.002+01:002008-05-28T10:27:30.011+01:00Cross-Thread com Anonymous Methods<span xmlns="xmlns"><p>Quando desenvolvemos aplicações clientes é comum criar threads para executar tarefas sem que o Form fique bloqueado, sem responder ao utilizador nem actualizar a sua aparência. Até aqui tudo bem, mas imaginemos que queremos por exemplo alimentar uma lista com mensagens ou alterar propriedades de alguns controlos. Se o tentarmos fazer a partir da mesma thread onde está a correr o nosso processo, obtemos erros do tipo System.InvalidOperationException com a descrição "Cross-thread operation not valid: Control 'TextBox1' accessed from a thread other than the thread it was created on."<br /></p><p>O que se passa é que um componente que está no ecrã apenas pode ser modificado pela thread que gere o próprio ecrã. Como resolvemos isto? O método típico é com recurso a um delegate, assim:<br /></p><p><span style="font-family:courier new;font-size:10;"><span style="color:blue;">delegate void </span><span style="color:#2b91af;">UpdateLabelDelegate</span>(<span style="color:#2b91af;">Label</span> label1, <span style="color:blue;">string</span> text);<br /><span style="color:blue;">private void</span> updateLabel(<span style="color:#2b91af;">Label</span> label1, <span style="color:blue;">string</span> text)<br />{<br /><span style="color:blue;"> if</span> (label1.InvokeRequired)<br /> {<br /> label1.BeginInvoke(<span style="color:blue;">new </span><span style="color:#2b91af;">UpdateLabelDelegate</span>(updateLabel), label1, text);<br /><span style="color:blue;"> return</span>;<br /> }<br /> label1.Text = text;<br />}<br /><span style="color:blue;">void</span> MyThreadMethod()<br />{<br /><span style="color:green;"> //more code...</span></span><br /><span style="font-family:courier new;font-size:10;"> updateLabel(label1, <span style="color:#a31515;">"New text"</span>);<br /><span style="color:green;"> //more code...<br /></span>}</span><br /></p><p>O processo até é simples: verificamos se a thread actual pode modificar o componente (<span style="font-family:courier new;font-size:10;">label1.InvokeRequired</span>) e se não puder ser solicitamos à thread que suporta o componente que execute o nosso código, utilizando o delegate que lhe providenciamos. Não é complicado, mas não é muito agradável ter todo este código para simplesmente alterar o texto de uma Label ou uma qualquer propriedade de um outro componente no Form.<br /></p><p>Desde a versão 2.0 da Framework .Net que temos a possibilidade de criar Anonymous Methods. Com este recurso o código pode ficar muito mais simples:<br /></p><p><span style="font-family:courier new;font-size:10;"><span style="color:blue;">void</span> MyThreadMethod()<br />{<br /><span style="color:green;"> //more code...<br /></span> label1.BeginInvoke((<span style="color:#2b91af;">MethodInvoker</span>)<span style="color:blue;">delegate</span>() { label1.Text = <span style="color:#a31515;">"New text"</span>; });<br /><span style="color:green;"> //more code...<br /></span>}</span><br /></p><p>Ou seja, podemos actualizar os componentes directamente da thread onde estamos a trabalhar, com uma única linha de código. Bem mais interessante, não?</p></span>Luís Lopeshttp://www.blogger.com/profile/05302074901453864456noreply@blogger.com0