tag:blogger.com,1999:blog-1201611953533696132024-03-05T16:15:45.182-03:00Vitor Rubio Developer - Dicas de programaçãoDicas de Delphi, C#, javascript etcVitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.comBlogger200125tag:blogger.com,1999:blog-120161195353369613.post-47808107386158074722020-09-18T21:37:00.000-03:002020-09-18T21:37:00.575-03:006 maneiras de fazer a mesma coisa, o que é considerado boas práticas? <p>As vezes tem tantas maneiras diferentes de fazer o mesmo código que nós ficamos na dúvida quanto a qual maneira usar. O que seria considerado "boa prática" pela comunidade e o que sua equipe entenderia melhor. </p>
<p>Suponhamos que você esteja trabalhando dentro de um método de um Domain Service chamado UmDomainServiceChique(objetoDoDominio) que será chamado por uma API.</p>
<p>Você tem uma regra de negócio chique para ser verificada que por enquanto chamarei de VerificaMinhaRegraChiqueComplexa().</p>
<p>Você chama UmDomainServiceChique(objetoDoDominio) e caso VerificaMinhaRegraChiqueComplexa() retorne true você vai querer que UmDomainServiceChique faça o que tem que fazer e a api retornar Ok 200, caso contrário você quer que a API responda um erro qualquer, tipo BadRequest, e retornar uma mensagem dizendo que VerificaMinhaRegraChiqueComplexa deu ruim. </p>
<p>Eu vejo 6 maneiras de fazer isso, gostaria de saber a opinião de outrs devs sobre qual seria a maneira menos gambiarrística de fazer:</p>
<p>1) se VerificaMinhaRegraChiqueComplexa() for false disparo uma exception. Eu particularmente não gosto disso porque exceptions são lentas e quebram o fluxo de execução do sistema. Acho sujo. </p>
<pre><code class="lang-cs line-numbers" >
namespace MeuBreguetz.DomainServices
{
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public void UmDomainServiceChique(Obeeeeejeto objetoDoDominio)
{
if(VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
//faz o que tem q fazer boneeeeto
//salva
}
else
{
throw new MinhaExceptionZuada("Deu ruim porque a regra chique não valeu");
}
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
svc.UmDomainServiceChique(objeeeeeto);
return Ok();
}
}
}
</code></pre>
<p>2) retornar um boolean e um out parameter string com mensagem de erro. Eu não gosto de out parâmeters</p>
<pre><code class="lang-cs line-numbers">
namespace MeuBreguetz.DomainServices
{
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public bool UmDomainServiceChique(Obeeeeejeto objetoDoDominio, out string mensagem)
{
mensagem = "";
if(VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
//faz o que tem q fazer boneeeeto
//salva
return true;
}
else
{
mensagem = "Deu ruim porque a regra chique não valeu";
return false;
}
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
if (svc.UmDomainServiceChique(objeeeeeto, out string mensagem))
{
return Ok();
}
else{
return BadRequest(mensagem);
}
}
}
}
</code></pre>
<p>3) retornar void com dois out parameters, um boolean e um string com a msg de erro. Eu sempre tenho essa dúvida quando se trata de dois outputs: uso o return do método mais um parâmetro ou faço método void com dois parâmetros ?</p>
<pre><code class="lang-cs line-numbers">
namespace MeuBreguetz.DomainServices
{
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public void UmDomainServiceChique(Obeeeeejeto objetoDoDominio, out bool sucesso, out string mensagem)
{
mensagem = "";
sucesso = true;
if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
sucesso false;
mensagem = "Deu ruim porque a regra chique não valeu";
return; //ou não ....
}
//else ... dependendo da regra
//faz o que tem q fazer boneeeeto
//salva
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem);
if (sucesso)
{
return Ok();
}
else{
return BadRequest(mensagem);
}
}
}
}
</code></pre>
<p>4) retornar um value tuple. Eu particularmente não gosto de tuples do tipo Tuple<bool, string> por causa dos nomes Item1, Item2 ... e também não curto a sintaxe nova dos value tuples nomeados, acho bagunçado e acho que poucos membros no time entendem essa sintaxe nova. </p>
<pre><code class="lang-cs line-numbers">
namespace MeuBreguetz.DomainServices
{
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public (bool Sucesso, string Mensagem) UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
{
if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
return (false, "Deu ruim porque a regra chique não valeu");
}
//faz o que tem q fazer boneeeeto
//salva
return (true, "");
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
var resultado = svc.UmDomainServiceChique(objeeeeeto);
if (resultado.sucesso)
{
return Ok();
}
else{
return BadRequest(resultado.mensagem);
}
}
}
}
</code></pre>
<p>5) retornar um um DTO. Aí mais cedo ou mais tarde sua aplicação fica cheia de DTOs e você se encontra no inferno. Eles se espalham, e uma hora tomam a aplicação inteira. </p>
<pre><code class="lang-cs line-numbers">
namespace MeuBreguetz.DomainServices
{
public class InteligentíssimoDtoDeResultado
{
//aqui, a meu ver, tanto faz ser classe ou struct, imutável ou não, usar backed properties ou fields públicos ... dá no mesmo
public bool Sucesso {get; set;}
public string Mensagem {get; set;}
}
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public InteligentíssimoDtoDeResultado UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
{
if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
return new InteligentíssimoDtoDeResultado {Sucesso = false, Mensagem = "Deu ruim porque a regra chique não valeu"};
}
//faz o que tem q fazer boneeeeto
//salva
return new InteligentíssimoDtoDeResultado {Sucesso = true};
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
var resultado = svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem)
if (resultado.Sucesso)
{
return Ok();
}
else{
return BadRequest(resultado.Mensagem);
}
}
}
}
</code></pre>
<p>6) retornar um dynamic contendo um objeto anônimo e ver o mundo pegar fogo, perder todos os benefícios da checagem de tipo em design time </p>
<pre><code class="lang-cs line-numbers">
namespace MeuBreguetz.DomainServices
{
public class MeuDomainService()
{
public bool VerificaMinhaRegraChiqueComplexa(Obeeeeejeto objetoDoDominio)
{
return (DateTime.Now.Seconds % 2 == 0); // só de sacanagem
}
public dynamic UmDomainServiceChique(Obeeeeejeto objetoDoDominio) //vc fica com mais itens antes do nome do que depois, muito estranho
{
if(!VerificaMinhaRegraChiqueComplexa(objetoDoDominio))
{
return new {Sucesso = false, Mensagem = "Deu ruim porque a regra chique não valeu"};
}
//faz o que tem q fazer boneeeeto
//salva
return new {Sucesso = true};
}
}
}
namespace MeuBreguetz.API
{
public class MinhaApi
{
public IActionResult /*Ou coisa assim*/ Put(parametros) //a keep aew you
{
//...
var resultado = svc.UmDomainServiceChique(objeeeeeto, out bool sucesso, out string mensagem)
if (resultado.Sucesso)
{
return Ok();
}
else{
return BadRequest(resultado.Mensagem);
}
}
}
}
</code></pre>
<p>E aí? vamos votar? </p>
<p>Diga aí nos comentários, 1,2,3,4,5,6 ? </p>Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-39625262482922184222016-12-07T12:53:00.002-02:002016-12-14T18:17:57.910-02:00Como dar Permissão para o ApplicationPoolIdentity no sistema de arquivosAs vezes você está fazendo um website ou sistema web em Asp.Net que precisa ler e gravar um arquivo em uma determinada pasta. Geralmente é uma subpasta do proprio aplicativo.<br />
<br />
Quando você tenta rodar a aplicação recebe uma mensagem de erro dizendo que a aplicação não tem privilégios para gravar o dito cujo arquivo.<br />
<br />
Geralmente, quando isso acontecia, eu ia lá nas configurações avançadas do AppPool e trocava o <b>ApplicationPoolIdentity</b> por <b>NetworkService</b> ou coisa assim, e dava permissão na pasta para o <b>NetworkService</b>. Afinal o AppPool cria um usuário instantâneo para o <b>ApplicationPoolIdentity</b> e esse cara não existe no windows, não tem como dar permissão pra ele, certo? Errado.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvJXu47SCyGLSJXowS2MDOqfF562uCtxOIzRZirRWOsOVogXwQ0FYQCakIAbzWE-SNcllYu6x_jgT6bFneAVb0moSNokGQSDaDNMJl9dZDhcDuetLKGN7ghgSMNme3IJAep03iTWHRNOE/s1600/ConfigAppPool.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Propriedades do App Pool" border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvJXu47SCyGLSJXowS2MDOqfF562uCtxOIzRZirRWOsOVogXwQ0FYQCakIAbzWE-SNcllYu6x_jgT6bFneAVb0moSNokGQSDaDNMJl9dZDhcDuetLKGN7ghgSMNme3IJAep03iTWHRNOE/s320/ConfigAppPool.png" title="Propriedades do App Pool" width="212" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Geralmente o usuário é ApplicationPoolIdentity</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm36Girg_8dvEH0isbg83SU316obKzI761RJcWrb_02sT7aTMqmP-RoqyvBspyd-VD1VrOA0uLka6OREHvngcBZLIlfASTtBvx-KfzwT0RRVP4PodWuEvwCijCV7QNYG-bTwuSvrL4glU/s1600/contasAppPool.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Escolha de conta de sistema" border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm36Girg_8dvEH0isbg83SU316obKzI761RJcWrb_02sT7aTMqmP-RoqyvBspyd-VD1VrOA0uLka6OREHvngcBZLIlfASTtBvx-KfzwT0RRVP4PodWuEvwCijCV7QNYG-bTwuSvrL4glU/s320/contasAppPool.png" title="Escolha de conta de sistema" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Muita gente troca para NetworkService</td></tr>
</tbody></table>
<br />
<br />
<br />
<br />
Você pode dar permissão para o <b>ApplicationPoolIdentity</b> fazendo o seguinte: na hora de escolher o nome do usuário que terá acesso a pasta da sua aplicação (lá no inetpub/wwwroot/SeuApp/ você coloca o nome do seu AppPoll prefixado de <b>IIS AppPool\.</b><br />
<br />
Por exemplo: se o nome do seu AppPool é DefaultAppPool, então o nome do usuário (em local machine) é IIS AppPool\DefaultAppPool. Se é HelDesk, então IIS AppPool\HelpDesk e assim por diante.<br />
<br />
Na figura o nome do meu AppPool é DNN2, porque é o segundo appPool que criei para meu DotNetNuke. <br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Ot1wEDI4S_35TyKMeInq4iL9bLY07Kr3yBfF3Py6UOrJw06KlVayhWZoTHwsKUePu0Sa3vKCIQKUTDcliqeQ5h44sCg8LQTnPcSRWe-DZvG-KZUWjFh2Mzcjy4phJlVYy5Pi3PMRwN8/s1600/permissao.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="permissões de acesso ao sistema de arquivos" border="0" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Ot1wEDI4S_35TyKMeInq4iL9bLY07Kr3yBfF3Py6UOrJw06KlVayhWZoTHwsKUePu0Sa3vKCIQKUTDcliqeQ5h44sCg8LQTnPcSRWe-DZvG-KZUWjFh2Mzcjy4phJlVYy5Pi3PMRwN8/s320/permissao.png" title="permissões de acesso ao sistema de arquivos" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Digite iis apppool\NomeDoPool</td></tr>
</tbody></table>
Quando você digita IIS AppPool\NomeDoPool o usuário não existe, mas quando você verifica o nome (check names) o nome é substituído automaticamente pelo nome do AppPool, mas se você digitar o nome do appPool direto não funciona.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5hgA53fkTfXTy8_w6KnJtYJXBcIj6lLcXj6SXZrLRZjskd6lROgc6XbPLnPIMXQDysuPiG2kMzYvz1OxfoQvNgxhv5BHo6AZOY27ZcnC4_u5r7JGfzocKzRXlrS2m9x7LTS2tQ7poJk4/s1600/permissaoChecked.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Depois do check" border="0" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5hgA53fkTfXTy8_w6KnJtYJXBcIj6lLcXj6SXZrLRZjskd6lROgc6XbPLnPIMXQDysuPiG2kMzYvz1OxfoQvNgxhv5BHo6AZOY27ZcnC4_u5r7JGfzocKzRXlrS2m9x7LTS2tQ7poJk4/s320/permissaoChecked.png" title="Depois do check" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Depois de dar um Check o nome vira o próprio appPool</td></tr>
</tbody></table>
<br />
Fontes<br />
<a href="http://stackoverflow.com/questions/7334216/iis7-permissions-overview-applicationpoolidentity">http://stackoverflow.com/questions/7334216/iis7-permissions-overview-applicationpoolidentity</a><br />
<a href="https://www.iis.net/learn/manage/configuring-security/application-pool-identities">https://www.iis.net/learn/manage/configuring-security/application-pool-identities</a><br />
<a href="http://stackoverflow.com/questions/5437723/iis-apppoolidentity-and-file-system-write-access-permissions">http://stackoverflow.com/questions/5437723/iis-apppoolidentity-and-file-system-write-access-permissions</a><br />
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-14820762634891074962016-12-02T15:22:00.000-02:002016-12-14T18:17:37.869-02:00Formatando um item ou membro de enum para texto amigávelMuitas vezes nós criamos Enums para expressar possíveis opções/valores de um campo de múltipla escolha onde os itens são fixos do sistema e não cadastrados em uma tabela.<br />
Há casos em que os itens definem regras de negócio e rumos a tomar na aplicação. Nesses casos usar enum não é a melhor opção.<br />
Em todos os outros casos usar enum pode ser legal, mas existe um problema: como popular um combo box / dropdown list com os itens do combo com nomes amigáveis? Sim, você não pode colocar espaços e caracteres especiais em um enum. Mas ao popular as opções, seja em uma aplicação windows forms ou web forms, você pode querer mostrar descrições longas e cheias de acentos e caracteres especiais para as opções no dropdown.<br />
Você pode usar os atributos Description ou EnumMember para definir programaticamente essas descrições longas, mas obter esses valores de volta vai algumas linhas de código.<br />
Nesse código que eu compartilho abaixo escrevi um extension method (não abuse deles) para o tipo enum chamado ToText() que tenta obter o Description, se não existir tenta obter o EnumMember, e se não existir eu criei um outro, chamado text, para exemplificar como podemos adicionar a qualquer membro do código propriedades e valores declarativamente através de atributos.<br />
Você pode adaptar outros atributos, ou separar Description, EnumMember e Text em métodos separados se desejar.<br />
<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace VtrFramework.Extensions
{
/// <summary>
/// classe que permite usar um atributo texto em um item de enum, para ele ter uma descrição amigável
/// </summary>
public class TextAttribute : Attribute
{
public string Text;
public TextAttribute(string text)
{
Text = text;
}
}
/// <summary>
/// Adiciona um método a mais em um elemento do tipo enum para pegarmos seu texto amigável
/// </summary>
public static class EnumExtensions
{
/// <summary>
/// Dado um enum, retorna seu correspondente string que pode ser: "" se ele for null, Seu decorator/atributo Text se houver, ToString caso contrário
/// funciona também com o atributo Description e com o atributo EnumMember
/// </summary>
/// <param name="enumeration" />O Enum a ser convertido
/// <returns>string - O texto do enum</returns>
public static string ToText(this Enum enumeration)
{
if (enumeration == null)
{
return "";
}
MemberInfo[] memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
if (memberInfo != null && memberInfo.Length > 0)
{
try
{
object[] descrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (descrs != null && descrs.Length > 0)
{
return ((DescriptionAttribute)descrs[0]).Description;
}
object[] enumbs = memberInfo[0].GetCustomAttributes(typeof(EnumMemberAttribute), false);
if (enumbs != null && enumbs.Length > 0)
{
return ((EnumMemberAttribute)enumbs[0]).Value;
}
object[] txts = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
if (txts != null && txts.Length > 0)
{
return ((TextAttribute)txts[0]).Text;
}
}
catch
{
//catch mudinho porque o fallback é direto para o ToString
}
}
return enumeration.ToString();
}
}
}
</pre>
<br />
Use-o assim:<br />
<br />
<pre class="brush:csharp">
namespace VtrFramework.Test.Extensions
{
[TestFixture, Description("Teste de métodos de extensão para enuns"), Category("ExtensionMethods")]
public class EnumExtensionsTest
{
public enum TargetEnum
{
[System.ComponentModel.Description("Opção 1")]
Opcao1,
[EnumMember(Value ="Opção 2")]
Opcao2,
[Text("Opção 3")]
Opcao3,
Opcao4
}
[Test]
[Description("Teste de método que traz descrição amigável do enum")]
[Category("ExtensionMethods")]
public void ToTextTest()
{
Assert.AreEqual("Opção 1", TargetEnum.Opcao1.ToText());
Assert.AreEqual("Opção 2", TargetEnum.Opcao2.ToText());
Assert.AreEqual("Opção 3", TargetEnum.Opcao3.ToText());
Assert.AreEqual("Opcao4", TargetEnum.Opcao4.ToText());
}
}
}
</pre>
<br />
Você pode popular listbox e dropdowns assim:
<br />
<pre class="brush:csharp">
/// <summary>
/// Ferramentas para trabalhar com Enuns
/// </summary>
public class EnumTools
{
/// <summary>
/// publica os itens de um enum em um ListItemCollection
/// </summary>
/// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
/// <param name="lst">System.Web.UI.WebControls.ListItemCollection da ListBox ou DropDownList que vai ser preenchida</param>
/// <param name="primeiroVazio">true se o primeiro item for o vazio/default, false caso contrário</param>
/// <param name="textoPrimeiroVazio">texto do primeiro item, que não deve fazer parte do enum</param>
/// <param name="valorPrimeiroVazio">valor do primeiro item, que pode ser String.Empty, 0 ou null dependendo da regra</param>
public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.ListItemCollection lst, bool primeiroVazio = true, string textoPrimeiroVazio = "Escolha uma opção", string valorPrimeiroVazio = "") where TEnum : struct, IConvertible
{
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("TEnum precisa ser do tipo ENUM");
}
lst.Clear();
if (primeiroVazio)
{
lst.Insert(0, new System.Web.UI.WebControls.ListItem(textoPrimeiroVazio, valorPrimeiroVazio));
}
var valores = Enum.GetValues(typeof(TEnum));
foreach(var v in valores)
{
string text = ((Enum)v).ToText();
string value = ((int)v).ToString();
lst.Add(new System.Web.UI.WebControls.ListItem(text, value));
}
}
/// <summary>
/// publica os itens de um enum em um DropDownList
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <param name="drop">o DropDown/ComboList a ser preenchido</param>
/// <param name="primeiroVazio">true se o primeiro item for o vazio/default, false caso contrário</param>
/// <param name="textoPrimeiroVazio">texto do primeiro item, que não deve fazer parte do enum</param>
/// <param name="valorPrimeiroVazio">valor do primeiro item, que pode ser String.Empty, 0 ou null dependendo da regra</param>
public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.DropDownList drop, bool primeiroVazio = true, string textoPrimeiroVazio = "Escolha uma opção", string valorPrimeiroVazio = "") where TEnum : struct, IConvertible
{
PublicaEnum<TEnum>(drop.Items, primeiroVazio, textoPrimeiroVazio, valorPrimeiroVazio);
}
/// <summary>
/// publica os itens de um enum em um RadioButtonList
/// </summary>
/// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
/// <param name="rbl">o RadioButtonList a ser publicado</param>
public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.RadioButtonList rbl) where TEnum : struct, IConvertible
{
PublicaEnum<TEnum>(rbl.Items, false);
}
/// <summary>
/// publica os itens de um enum em um ListBox
/// </summary>
/// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
/// <param name="lbx">o ListBox a ser publicado</param>
public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.ListBox lbx) where TEnum : struct, IConvertible
{
PublicaEnum<TEnum>(lbx.Items, false);
}
}
</pre>
Isso ajuda bastante na hora de criarmos listas com as UF's do Brasil, por exemplo. Veremos isso num próximo post.Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-29994354275788639542015-08-06T08:14:00.001-03:002016-12-14T18:15:26.667-02:00O absurdo da notação húngara nos dias atuais<div>
Define-se por <a href="http://pt.wikipedia.org/wiki/Nota%C3%A7%C3%A3o_h%C3%BAngara" style="font-family: 'Helvetica Neue Light', HelveticaNeue-Light, helvetica, arial, sans-serif;">notação húngara</a> <span style="font-family: "helvetica neue light" , , "helvetica" , "arial" , sans-serif;">a prática de prefixar variáveis com letras que indiquem o seu tipo. Por exemplo i para inteiros, d para datas, f para floats. </span></div>
<div>
<br /></div>
<div>
</div>
<div>
As variáveis data de nascimento e nome em notação húngara seriam ddatanascimento e snome, no pior dos casos, ou dDataDeNascimento e sNome se o "programador" resolveu usar camelCase. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Como mencionei nos meus artigos anteriores, e como mencionado nos livros "Código Limpo" e qualquer livro sobre XP, essa prática caiu em desuso. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Ela foi útil um dia para identificar o tipo das variáveis, e de fato identificava. Hoje damos nomes significativos para as variáveis e deixamos que sua declaração e as facilidades da IDE identifiquem o seu tipo. Além disso hoje podemos mudar o tipo de uma variável mantendo o seu nome e o seu uso, coisa que no passado geraria alguma inconsistência semântica na hora de ler e dar manutenção no código. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Soma-se a isso o fato de no passado não existirem, nas linguagens comumente usadas, tipos de dados dinâmicos (variants se aproximavam disso) ou definidos em tempo de execução, tampouco tipos anônimos. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Num contexto orientado a objetos o uso de notação húngara, além de ser um overhead, é ridículo e chega a ser prejudicial. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Já vi, em várias empresas, classes em C# ou Java prefixadas com "cls". Qual o propósito disso? A notação húngara foi criada para se prefixar variáveis, e nunca tipos ou records. Uma classe é um tipo definido pelo programador, um tipo estruturado, uma classe é um tipo, portanto nunca deveria ser prefixado com a abreviação de um tipo. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Qual o propósito de prefixar as classes com cls se TODAS as classes sem exceção forem prefixadas com cls? No que cls as distingue das outras? </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Pense na diferença entre dizer que todos os animais são do tipo animal, e todos os tipos são do tipo tipo. Redundância. Sempre é prejudicial. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Prefixar classes com cls não as distinguem umas das outras, mas o pior é prefixar objetos dessas classes, que podem ser inúmeras e com inúmeros significados, com a letra "o", só porque são objetos. É afirmar erroneamente e categoricamente que os objetos oUsuario e oProduto são do mesmo tipo, quando suas classes sequer tem algum grau de parentesco. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Usar notação húngara em programas modernos e linguagens orientadas a objetos é sinal de acomodação profissional, falta de atualização, porquice ou até mesmo estupidez. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Linguagens como Object Pascal e as IDE's Delphi e Lazarus te obrigam a usar notação húngara na criação de classes por um motivo "legado": o código nestas linguagens tem dois níveis de encapsulamento, a unit e a classe/type. Isso faz com que a própria unit seja um "tipo" e seu nome faz parte do namespace total das classes que estão dentro dela. Como o pascal permite variáveis (públicas ou privadas) estáticas fora das classes (globais), não é permitido que a unit tenha o mesmo nome de sua classe, pois isso geraria dois "tipos" com o mesmo nome. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Veja que é uma limitação do Delphi / Lazarus: mesmo que você obedeça a orientação e boa prática de ter uma única classe por unit/arquivo, uma classe não pode ter o mesmo nome do arquivo físico onde está contida. E o arquivo físico deve ter o mesmo nome que seu nome "lógico" de unidade. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Em contraste com isso linguagens como C# e Java permitem ter classes com o mesmo nome que o arquivo onde elas estão contidas, e isso não te impede de criar outras classes com outros nomes dentro do mesmo arquivo embora isso não seja uma boa prática. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Embora o uso de notação húngara seja justificado no caso do Delphi e do Lazarus, eu acredito que prefixar ou sufixar os arquivos com a letra u (de unit) é melhor do que prefixar os tipos. Assim você tem os tipos de dados, as suas classes, os seus objetos de negócio ( o seu domínio ) com nomes significativos, sem problemas de semântica e com um dicionário padrão do domínio. Isso traria um padrão de nomenclatura mais moderno para quem programa nessas linguagens. Mas nem tudo são flores...</div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Por padrão das units de sistema e dos frameworks que acompanham as ferramentas todas as classes (e tipos, records etc) são prefixadas com a letra T (de type) . Então todas as classes de sistema já existem e são prefixadas com T. Não faz sentido você criar uma classe Produto, mas na hora de colocar vários produtos numa lista precisar de uma TList<Produto>. O uso de prefixo de um lado e não do outro pode gerar um gap semântico. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Além disso tem o problema das interfaces. As modernas técnicas de POO e DDD e os princípios SOLID nos ensinam a programar orientado a interfaces, e grandes nomes do projeto e desenvolvimento de software, como Kent beck, Robert Martin, Martin Fowler afirmam categoricamente que: </div>
<div>
</div>
<div>
<ol>
<li>Você deve usar as modernas técnicas de POO, padrões de projeto e DDD e </li>
<li>Você deve usar padrões de nomenclatura, codificação e formatação para nivelar a sua equipe com um mesmo estilo de codificação e todos progredirem rápido. </li>
</ol>
<div>
O problema disso é que os melhores <a href="http://blog.vitorrubio.com.br/2015/03/modernos-padroes-de-nomenclatura-de.html">padrões de nomenclatura</a> encontrados na literatura hoje afirmam que as interfaces devem ser prefixadas com I .... olha a notação húngara aí geeeeeente!. </div>
</div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Acredito que não dá para ser dogmático a ponto de não prefixar as interfaces com I. Se você ver uma interface chamada "Pessoa" é meio difícil saber que é uma interface sem olhar na sua declaração, seus métodos "pelados" e falta de implementação. Ainda assim ela pode ser confundida com uma classe abstrata. Até na UML existem estereótipos e símbolos diferentes para definir as interfaces. </div>
<div>
</div>
<div>
<br /></div>
<div>
</div>
<div>
Mas, se você não estiver escrevendo uma interface e nem usando Object Pascal, Pelo amor de Deus, não usem mais notação húngara.</div>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-53488900883340447062015-03-20T01:19:00.004-03:002015-03-20T01:19:30.895-03:00Modernos padrões de nomenclatura de codificação<div style="font-family: Tahoma; orphans: 2; text-align: -webkit-auto; widows: 2;">
Os padrões apresentados aqui são fruto de uma pesquisa em 2 livros e 4 sites, experiências profissionais do autor, consenso do mercado e recomendações de práticas da Microsoft. Como qualquer convenção ou tecnologia, este não é 100% correto, não é uma verdade absoluta e não é uma bala de prata. São apenas guidelines para que todos nós escrevamos bom código, código limpo e livre de bad smells e que possamos entender e melhorar os códigos uns dos outros, evoluindo como equipe. Nesse texto eu quis expressar não somente regras de nomenclatura e codificação, mas também apresentar algumas boas práticas para um código mais coeso e flexível.<br />
Esses são os padrões que adotamos na empresa onde trabalho e não há nenhum motivo especial para você e sua equipe adotarem este. Os padrões de codificação devem ser um consenso da equipe.<br />
Estes foram elaborados com ajuda de outros padrões prontos de outras empresas, unindo o que eu achei de melhor nos padrões da Microsoft e nas práticas já consolidadas da comunidade.<br />
<br />
<br />
<h3>
<span style="font-size: large;">"É impossível para um homem aprender aquilo que ele acha que já sabe."</span><span style="font-size: large;"> - Epíteto</span></h3>
<br />
<br />
Em se definindo e aplicando “Padrões de Codificação e Documentação”, há um enorme ganho com facilidade de implementação e melhorias no código em:<br />
<br />
<ul>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Visibilidade;</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Portabilidade;</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Reaproveitamento;</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Redução de tempo em:</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Adaptação de novos desenvolvedores.</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Manutenção;</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Migração;</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Identificação, rastreamento e correção de erros.</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span>Diminuição de reescrita de código por falta de documentação.</li>
</ul>
<br />
<br />
Fonte: <a href="http://blog.walkeralencar.com/archives/233">http://blog.walkeralencar.com/archives/233</a><br />
<br />
<br />
Coding standards tem sido alvo de várias disciplinas, e tratado em vários livros de programação e boas práticas. Alguns livros que abordam o tema são livros de XP e o Código Limpo, ambos abordando outros aspectos do bom código e da disciplina dos programadores além do aspecto dos padrões de codificação.<br />
<br />
A própria microsoft já fornece, em seu principal veículo de comunicação, msdn, os padrões de codificação. Isso garante, por exemplo, que qualquer programador recém-contratado do mercado já esteja hasbituado com os padrões de codificação.<br />
<a href="https://msdn.microsoft.com/en-us/library/ff926074.aspx">https://msdn.microsoft.com/en-us/library/ff926074.aspx</a><br />
Recomendo a adoção deste padrão com algumas alterações muito comuns na comunidade.<br />
<br />
<br />
<br />
<h3>
Nossas Regras</h3>
A regra geral é seguir as convenções e práticas do próprio .net framework (que foram adotadas como padrão pelo mercado) e manter a consistência.<br />
<br />
<br />
<h4>
Definições de casing conventions:</h4>
<i>PascalCase/UpperCamelCase</i> - Consiste em começar com maiúscula e usar maiúscula na inicial de cada palavra composta. Exemplo: FuncionarioMensalista<br />
Geralmente é utilizada para nomear propriedades e campos públicas e métodos (públicos ou privados). Também deve ser usado para nomear constantes.<br />
<br />
<i>camelCase </i>- Consiste em se iniciar com minúscula e usar maiúscula para a primeira letra de cada palavra composta. Exemplo: funcionarioMensalista<br />
Geralmente são usados em nomes de variáveis locais e propriedades privadas.<br />
<br />
<br />
<h4>
Notação Húngara</h4>
Os padrões de nomenclatura da comunidade C# em geral dizem para não confiar o tipo de uma variável a seu nome:<br />
<i>"Do not rely on the variable name to specify the type of the variable. It might not be correct."</i><br />
Isso põe por terra todo o conceito antiquado de notação húngara. ( <a href="http://pt.wikipedia.org/wiki/Nota%C3%A7%C3%A3o_h%C3%BAngara">http://pt.wikipedia.org/wiki/Nota%C3%A7%C3%A3o_h%C3%BAngara</a> )<br />
Outras coisas que põe por terra a notação húngara são as boas práticas de se criar nomes significativos para variáveis e métodos (XP, Código Limpo), que expressem ação e intenção e que dispensam comentários.<br />
Outra crescente desvantagem da notação húngara é que com os frameworks e ides cada vez mais completos um número cada vez maior de classes prontas, componentes e widgets vêm empacotados com os produtos que usamos (visual studio e .net framework) fora os adquiridos de terceiros e os open-source.<br />
Criar uma abreviação de duas ou três letras para cada tipo destes torna-se um verdadeiro inferno.<br />
Notação húngara já é um conceito bem antigo e com certeza seu uso traz muitas desvantagens. Tipos dinâmicos e definição de tipo em runtime perdem todo o sentido com notação húngara, e não é necessário visto que a IDE pode vasculhar e te mostrar todos os atributos de uma variável.<br />
Quando você cria suas classes você cria seus tipos de dados com lógica própria. E frequentemente renomeamos nossas classes, mudamos, extraímos uma da outra, juntamos, derivamos. Fica impossível arrumar uma abreviação consistente para todas elas.<br />
<br />
<br />
<h4>
Noções gerais ausentes no padrão da Microsoft</h4>
Embora os padrões da microsoft abordem o tema das chaves, arrays, linhas e espaços em branco (assuntos ausentes nos nossos padrões), ela não aborda os padrões de nomenclatura (definidos como notação húngara nos nossos padrões mais antigos).<br />
É uma prática comum nas linguagens derivadas de c, ao se nomear campos privados dos quais dependem propriedades (públicas ou privadas), nomear em lowerCamelCase precedido de _.<br />
Outra prática comum é nomear constantes todas em MAIUSCULAS. Isso torna claro que o identificador é somente leitura, além de tornar claro seu tipo e que está relacionado à uma regra de negócio e não à arquitetura do software ou da informação, porém existem recomendações no mercado para não usá-las, portanto seguiremos as recomendações e não usaremos. Nomes de constantes em maiúsculas atraem muito a atenção do programador, distraindo-o, além de não ser consistente com o .net framework.<br />
Não se deve usar _ entre as palavras de um método, priopriedade ou variáveis, no entanto isso pode ser tolerado em uma constante.<br />
Um nome deve identificar um elemento (quem ele é) e não generalizá-lo. Além disso deve indicar o que o elemento faz e para que serve, não o que ele é.<br />
<br />
<br />
<h4>
Metáfora</h4>
Todo sistema deve ter uma metáfora que o defina em poucas palavras. Isso ajuda a equipe a formar um vocabulário comum do domínio da aplicação (ou das aplicações) e falarem a mesma língua. Também ajuda na escolha de bons nomes para os projetos e seus componentes. Bons nomes são essenciais para um software coeso e auto-documentável. Bons nomes dispensam comentários ou documentações complexas. Se for gastar um tempo desenvolvendo um software, comece gastando um bom tempo para o seu nome. O mesmo vale para uma classe ou método: tome tempo para escolher um bom nome. Isso te ajudará a manter <b>o princípio da responsabilidade única</b> e <b>o princípio da segregação de interface</b>.<br />
Use nomes significativos e pronunciáveis. Use nomes que expressem propósito.<br />
Sistemas amplamente usados são baseados em metáforas, por exemplo o sistema de arquivos do Windows é baseado na metáfora do Arquivo (armários para se guardar fichas / pastas).<br />
Essas ideias estão em acordo com os princípios do XP e do DDD.<br />
<br />
<br />
<h4>
Solution </h4>
A solution pode agrupar uma série de projetos / programas que são parte de um mesmo sistema, por isso dê um nome para a solution condizente com a metáfora do sistema. A ideia expressa pela solution deveria ser compartilhada pelos seus projetos.<br />
Exemplo: ServiceDesk<br />
<br />
<br />
<h4>
Projetos</h4>
Use a solution como base ou prefixo para o nome dos projetos, e coloque seu objetivo e/ou ambiente como sufixo. Se o seu projeto for dividido em camadas físicas, como Core, DAL/Data, Domain, GUI use esses nomes para identificar a camada a que pertence o projeto.<br />
Exemplo: ServiceDesk.Web<br />
<br />
<br />
<h4>
Arquivos</h4>
Salvo raras exceções, cada arquivo.cs deve ter apenas uma classe, e o nome do arquivo deve ser o nome desta classe. Uma exceção são os arquivos de partial classes, esses devem ter um sufixo que identifiquem o propósito do arquivo ou o porque dele estar separado. Por exemplo designer ou generated<br />
Exmeplos: <i>Default.cs Default.design.cs</i><br />
<b>Porque:</b> isso é consistente com as práticas da Microsoft no source do próprio .net. Arquivos são ordenados alfabeticamente pelo SO, e isso ajuda arquivos de classes parciais a permanecerem adjacentes.<br />
<br />
<br />
<h4>
Namespaces</h4>
Use PascalCase para nomear os namespaces. Use uma estrutura clara e bem definida.<br />
Exemplo: <i>NomeDaEmpresa.NomeDoProjeto.NomeDaCamada.NomeDoModulo.NomeDoComponente</i><br />
<i> BBI.ServiceDesk.Web.Data.Services.Repository</i><br />
<b>Porque</b>: é consistente com as práticas da Microsoft e mantém uma boa organização da sua base de código.<br />
<br />
<br />
<h4>
Classes</h4>
Use PascalCase para nomear classes. Use substantivos ou predicados nominais em caso de palavras compostas. Não use verbos.<br />
Exemplo: <i>Funcionario, GrupoDeFuncionario, ProdutoComposto</i><br />
<b>Porque</b>: classes são tipos de objetos, mini programas, devem expressar um conceito e não uma ação. Um conceito é melhor expresso por substantivos e adjetivos do que por verbos. Isso é consistente com as práticas da Microsoft e mais fácil de ler.<br />
<br />
<br />
<h4>
Interfaces</h4>
Use PascalCase para nomear interfaces, mas prefixe as mesmas com I. Isso ajuda a diferenciar interfaces de classes abstratas ou outros tipos de dados, ajuda a identificar o que as classes que as implementam fazem, e é uma prática comum do mercado desde a época do COM/COM+.<br />
Use substantivos, predicados nominais ou adjetivos/advérbios para nomear interfaces.<br />
Exemplos: <i>IEnumerable, IList, IHierarchyData, IEntity</i><br />
<b>Porque</b>: Isso é consistente com os padrões da Microsoft e do COM/COM+, além disso interfaces podem ser usadas para decorar classes, como flags, ou usadas como atributos. Por issp interfaces podem ser nomeadas com adjetivos ou advérbios, pois elas modificam ou segregam comportamento de outras classes. <br />
Interfaces são a base da abstração e da segregação de responsabilidade. São contratos entre duas partes, ou pontos de encaixe entre componentes. Programe orientado a interfaces e não à implementação.<br />
<br />
<br />
<br />
<h4>
Ordem dos elementos</h4>
Declare todas as variáveis membro no topo da classe, com as estáticas acima de todas. Utilize a ordem:<br />
<b>Membros/Fileds</b><br />
<br />
<br />
<ol>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> privadas estáticas</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> públicas estáticas (evite-os a todo custo)</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> privadas de instância</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> públicas de instância (evite-os, transforme-os em propriedades sempre que possível)</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> propriedades protegidas</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> propriedades públicas de instância</li>
</ol>
<br />
<br />
<br />
<b>Métodos </b>(na ordem do mais genérico/abstrato para o mais específico, dos métodos que chamam outros para os chamados)<br />
<br />
<br />
<ol>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Construtores e Destrutores </li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Factory methods públicos de classes (são construtores especializados)</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Métodos públicos de classe</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Métodos privados de classe</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Métodos públicos de instância</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Métodos protegidos de instância</li>
<li><span class="Apple-tab-span" style="white-space: pre;"> </span> Métodos privados de instância</li>
</ol>
<br />
<br />
<b>Porque</b>: é uma prática geralmente aceita, evite que se fique procurando por variáveis, garante que a leitura de um source seja como a leitura de um artigo de jornal: dados genéricos em cima, dados detalhados abaixo, com nível crescente de granularidade e decrescente de abstração de cima para baixo. Para isso os métodos que são chamados por outras classes ficam acima, e os chamados pela própria classe abaixo. Com isso você precisa ler apenas o topo da classe para saber o que ela faz e como ela funciona apenas visualizando sua interface implícita sem se aprofundar em sua implementação.<br />
<br />
<br />
<h4>
Propriedades (privadas/protegidas/públicas)</h4>
Use PascalCase para o nome de propriedades. Use preferencialmente substantivos e predicados nominais.<br />
Exemplo: <i>Nome, DataNascimento</i><br />
<b>Porque</b>: além de facilitar a leitura, trata-se de objetos pertencentes a outro, como peças de algo maior, portanto todos substantivos. Está de acordo com as práticas da Microsoft para o .net<br />
<br />
<br />
<h4>
Fields ou Variáveis de instância ou Member Variables</h4>
<br />
<ul>
<li> Públicos : não devem existir</li>
<li> Privados: aplicar camelCase precedido de _</li>
</ul>
<br />
Exemplo: <i>_dataNascimento </i><br />
<b>Porque</b>: Está em acordo com as práticas comuns do mercado para linguagens derivadas de _, ajuda a separar os campos privados dos argumentos de métodos / constructors sem a necessidade do uso do this, isola essas variáveis da digitação acidental (porque obriga a digitação do _ no início, excluindo-as do intellisense / autocomplete). <br />
<br />
<br />
<h4>
Variaveis Locais</h4>
Use camelCase para os nomes de variáveis locais, use nomes significativos, evite prefixos e abreviações a não ser que sejam bem conhecidas, não use notação polonesa.<br />
Exemplo: <i>enderecoServidor, connectionString</i><br />
<b>Porque</b>: além de ser fácil de ler é consistente com a metodologia da Microsoft <br />
<br />
<br />
<h4>
Métodos</h4>
Use PascalCase para nomear os métodos. Use o formato Verbo ou Verbo+Complemento para nomear os métodos. Se o verbo for intransitivo o método não deveria ter parâmetros.<br />
Exemplo: <i>Salvar(grupoDeFuncionario)</i><br />
<i> Excluir(tipoDeTarefa)</i><br />
<i> ListarEntreDatas(dataInicial, dataFinal)</i><br />
<b>Porque</b>: Consistente com o .net framework e fácil de ler. Verbos expressam ações, por isso são melhores que substantivos para expressar métodos. É natural se ler e escrever dessa forma<br />
<br />
<br />
<br />
<h4>
Argumentos de Métodos</h4>
Use camelCase para argumentos de métodos, use substantivos. Se o nome de um método contém um verbo, os argumentos devem ser complementos desse verbo.<br />
Exemplo: <i>CalcularReajuste(porcentagemAumento)</i><br />
<i> Salvar(grupoDeFuncionario)</i><br />
<i> Excluir(tipoDeTarefa)</i><br />
<i> ListarEntreDatas(dataInicial, dataFinal)</i><br />
<b>Porque</b>: mais fácil de ler e entender. Tudo que pode ser verbalizado pode ser melhor armazenado pelo nosso cérebro. É condizente com as práticas da Microsoft no .net.<br />
<br />
<br />
<h4>
Ainda Sobre Argumentos de Métodos</h4>
Se você precisar de de mais de 3 argumentos no seu método e/ou precisar usar parâmetros nomeados há uma grande chance de você estar simplesmente enrolado e seu método precisar ser refatorado. Verifique se seu método não está com responsabilidades demais.<br />
Se você passa argumentos booleanos ou enums para um método onde ele tomará uma ação diferente dependendo do parâmetro é uma evidência clara de que você precisa decompor este em dois ou mais métodos. Dê uma olhada nos padrões de projeto GOF "Template Method" e "Strategy" que eles podem de dar uma ideia de como refazer estes métodos.<br />
<b>Porque</b>: Métodos grandes são difíceis de ler e de manter. Eles tendem a crescer mais a cada manutenção com a adição de desvios condicionais para fazerem coisas diferentes dependendo de configuração ou parâmetros. Esses métodos degradam o sistema rapidamente, ficando com código inatingível (nunca executado), código comentado e código com side effects (statefull) que não podem ser testados.<br />
<br />
<br />
<h4>
Parâmetros-Tipo (type parameters)</h4>
Type Parameters são os parâmetros que representam um tipo em uma expressão que usa generics. Por exemplo na definição de List<T> T é o type parameter. Na definição de classes genéricas sempre use PascalCase precedido de T para nomear os type parameters.<br />
Exemplo: <i>Repository<TEntity> : IRepository<TEntity> where TEntity : Entity</i><br />
<br />
<h4>
Strings</h4>
Concatene strings pequenas com sinal de " + " porém use StringBuilder para strings grandes. Use string.Format para strings pré formatadas e substituição de placeholders.<br />
<b>Porque</b>: Embora tenha sobrecarga de operadores nativa para parecer um value type pimitivo as strings são objetos (reference types). Isso significa que a cada atribuição ou concatenação de duas strings, dois objetos são destruídos e um novo é criado. Isso cria um grande overhead, principalmente dentro de loops. StringBuilder é uma classe que concatena várias strings de uma só vez sem precisar destruir e recriar a cada adição fazendo um uso mais inteligente da memória. Foi feito para ser usado em loops onde muitas strings são concatenadas, como uma saída html por exemplo.<br />
<br />
<br />
<br />
<h4>
Enums</h4>
Use PascalCase. Use substantivos no singular se for um Enum comum. Se for um Enum do tipo bit field / flags (a serem combinados múltiplos valores com o operador "|") pode-se usar substantivos no plural, pois sugere que mais de um valor pode ser usado.<br />
Exemplo:<br />
<div>
<pre class="brush:csharp">enum Importance
{
None,
Trivial,
Regular,
Important,
Critical
};
</pre>
<blockquote style="border: none; font-family: Tahoma; margin: 0px 0px 0px 40px; orphans: 2; padding: 0px; text-align: -webkit-auto; widows: 2;">
<br /></blockquote>
</div>
<b>Porque</b>: Consistente com o .net framework e mais natural para ler<br />
<br />
<br />
<h4>
if ... else if ... else</h4>
Sempre coloque um bloco de código com { } em estruturas de decisão if pulando uma linha antes de { e outra ante de }. Mesmo com if's que só terão uma linha de código.<br />
Se você precisar de mais de 3 níveis de aninhamento para uma estrutura if ou case significa que você está enrolado. Provavelmente seu método faz coisas demais ou sua classe tem muitas responsabilidades e muitos motivos pra mudar. <br />
<b>Porque</b>: if (b1) if (b2) Foo(); else Bar(); // consegue dizer ao primeiro golpe de vista a qual if pertence o else? <br />
<br />
<br />
<h4>
Case ... default</h4>
Sempre tenha um label default em uma estrutura case. Mesmo se ele nunca devesse ser atingido. Coloque nele código para disparar uma exceção caso um parâmetro inválido tenha sido erroneamente enviado para o case analizar.<br />
<br />
<br />
<br />
<h4>
Loops</h4>
Se você precisar de dois níveis de loops aninhados considere transformar o mais interno em um método privado. Se você estiver trabalhando com mais 3 níveis verifique se o método e/ou a classe não estão com responsabilidades demais e se não estão intestáveis.<br />
Jamais altere a variável de controle do loop for ou foreach dentro do loop. Isso pode levar a loops infinitos.<br />
<br />
<br />
<br />
<h4>
Alinhamento vertical de chaves</h4>
Alinhe as chaves verticalmente. Não mantenha a chave no final da linha, quebre a linha antes da chave e mantenha elas alinhadas. Sempre abra e feche as chaves em novas linhas.<br />
<div>
<div style="font-family: Tahoma; orphans: 2; text-align: -webkit-auto; widows: 2;">
<span style="color: #41ad1c;"><b>Certo</b>:</span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> </span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">public</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">virtual</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">void</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">setMensagemExplicacao(</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">string</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">mensagem)</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> {</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> MensagemExplicacao = mensagem;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.Visible =</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">true</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.InnerText = mensagem;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> }</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"><br /></span></span></div>
<div style="font-family: Tahoma; orphans: 2; text-align: -webkit-auto; widows: 2;">
<span style="color: red;"><b>Errado:</b></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> </span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">public</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">virtual</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">void</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">setMensagemExplicacao(</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">string</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">mensagem)</span></span><span style="color: #010101; font-family: Consolas; font-size: 9pt;">{</span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> MensagemExplicacao = mensagem;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.Visible =</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">true</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.InnerText = mensagem;</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> }</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"><br /></span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> </span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">public</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"> </span><span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">virtual</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">void</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> setMensagemExplicacao(</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">string</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"> <span style="font-size: 9pt;">mensagem)</span></span><span style="color: #010101; font-family: Consolas; font-size: 9pt;">{</span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> MensagemExplicacao = mensagem;</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.Visible = </span></span><span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">true</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"> <span style="font-size: 9pt;">;</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> lgdExplicacao.InnerText = mensagem;</span></span><span style="color: #010101; font-family: Consolas; font-size: 9pt;">}</span></div>
</div>
</div>
<br />
<b>Porque</b>: Chaves abertas ou fechadas no final de uma linha de código passam despercebidas e não são legíveis. O código pode ser confundido como parte do código acima.<br />
<br />
<br />
<h4>
Espaços em branco</h4>
Deixe espaços em branco entre os operadores e seus operandos. Isso facilita a leitura. <br />
Deixe espaços em branco entre um if, for ou foreach e sua expressão. Exemplo: if (UmFuncionario.Equals(EsteFuncionario))<br />
<br />
<br />
<h4>
Quebra de linhas</h4>
Quebre linhas antes de abertura e fechamento de chaves, quebre linhas para separar ideias, agrupar conceitos relacionados, separar conceitos não relacionados, separar a declaração de variáveis de seu uso, quebrar cadeias longas de caracteres ou encadeamentos longos de chamadas de métodos ou propriedades.<br />
Também é bom quebrar as linhas em chamadas de funções com listas de parâmetros muito longas, e edentar esses parâmetros.<br />
Quebre linhas antes e depois de regions, antes e depois de um using, e separando os fornecedores na lista de usings.<br />
<br />
<h4>
Regions</h4>
Use regions para agrupar conceitos e separar interface de implementação, eventos de métodos e de variáveris.<br />
Não use regions aninhadas pois isso impõe complexidade desnecessária.<br />
Não use regions para esconder código comentado, sujeira e gambiarras.<br />
<br />
<h4>
Indentação/Recuo</h4>
Use a indentação padrão do C# no visual studio (um tab = 4 espaços). Indente conceitos subordinados. Se precisar separar cadeias longas de chamadas em linhas, ou cadeias longas de parâmetros quebradas em linhas. Quebre as linhas de uma sentença SQL e Intente o SQL.<br />
Exemplo:<br />
<div>
<blockquote style="border: none; font-family: Tahoma; margin: 0px 0px 0px 40px; orphans: 2; padding: 0px; text-align: -webkit-auto; widows: 2;">
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> ChamadaDeFuncao(</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par1,</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par2,</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par3,</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par4,</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par5,</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> par6);</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> {</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> </span></span> <span style="color: green; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">//código</span></span></div>
<div align="left">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> }</span></span></div>
</blockquote>
</blockquote>
<div style="font-family: Tahoma; orphans: 2; text-align: -webkit-auto; widows: 2;">
<b style="font-size: 16px;"> </b><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> </span></span> <span style="color: #2b91af; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">Modulo</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">obj = session</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .CreateCriteria<</span></span> <span style="color: #2b91af; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">Modulo</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">>()</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .SetTimeout(120)</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .SetLockMode(</span></span> <span style="color: #2b91af; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">LockMode</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">.None)</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .SetCacheable(</span></span> <span style="color: blue; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">true</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">)</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .Add(</span></span> <span style="color: #2b91af; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">Restrictions</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">.Eq(</span></span><span style="color: #a31515; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">"Nome"</span></span> <span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">, nome))</span></span></div>
<div align="left" style="font-family: Tahoma; orphans: 2; widows: 2;">
<span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;"> .UniqueResult<</span></span> <span style="color: #2b91af; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">Modulo</span></span><span style="color: #010101; font-family: Consolas; font-size: xx-small;"><span style="font-size: 9pt;">>();</span></span></div>
<div style="font-family: Tahoma; orphans: 2; text-align: -webkit-auto; widows: 2;">
<b style="font-size: 16px;"> </b></div>
</div>
<br />
<h4>
Comentarios</h4>
Algumas definições dos nossos padrões foram feitas para VB antigo e se chocam diretamente com os padrões da microsoft, por exemplo o padrão de comentários:<br />
<i>"Do not create formatted blocks of asterisks around comments."</i><br />
Há comentários que prejudicam a legibilidade do código, não são atualizados no mesmo ritmo do código, sujam o mesmo e poderiam facilmente ser substituídos por nomes significativos<br />
Há comentários que simplesmente perdem o sentido pouco tempo depois de terem sido colocados, simplesmente porque o código logo abaixo deles ou o objetivo do sistema em si foi mudado.<br />
Não comente o código simplesmente para desativá-lo esperando que um dia vá precisar dele. Antes de dar check-in, delete o código comentado. Código comentado apenas emporcalha o sistema, deteriorando-o mais rápido. Outros programadores acharão que é importante e evitarão removê-lo. Se um dia, quando ele não for mais útil, ele acidentalmente for descomentado ele pode comprometer todo o funcionamento do sistema. Confie no seu sistema de versionamento.<br />
Não coloque cabeçalhos com informações de autor, versionamento, changelog e bugtracking em comentários. Confie no seu sistema de versionamento, faça os comentários de changelog ao dar check-in no sistema, controle o bugtracking com um sistema apropriado. Uma exceção à regra é quando há motivos legais para assegurar o autor do código, então pode existir um cabeçalho com o autor.<br />
Não comente o óbvio, coisas muito simples ou muito bem estabelecidas. Se um comentário óbvio se faz necessário, então na verdade é necessário renomear seu método para um nome que expresse seu propósito.<br />
Quando necessário, comente em uma linha separada (geralmente acima) e não na linha do código<br />
Comece o comentário com letra maiúscula e termine com um ponto<br />
Insira um espaço entre o // e o início do comentário<br />
<br />
<br />
<h4>
Comentários de documentação</h4>
Comentários de documentação são precedidos por /// e servem para definir a estrutura e uso de classes, métodos e propriedades para geração de documentação automática com ferramentas como Doxygene, NDoc e SandCastle.<br />
Como seu objetivo é documentar uma interface implícita ou API para uso de outros programadores, <b>comente apenas métodos e propriedades públicos e nunca comente membros privados.</b><br />
<b>Porque</b>: Isso está de acordo com o Princípio SOLID de programar voltado a interfaces e não implementação. Você não quer que outros programadores usem os métodos privados, então não há necessidade deles aparecerem na documentação. Assim você encapsula e protege o source em um nível adicional e está livre para mudar a implementação contanto que mantenha a mesma interface e funcionalidade.<br />
<br />
<br />
<br />
<h4>
Try ... Finally</h4>
Use o using sempre que seu bloco try ... finally servir apenas para chamar dispose em um recurso não gerenciado.<br />
Exemplo:<br />
<div>
<pre class="brush:c#">// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
{
((IDisposable)font1).Dispose();
}
}
// You can do the same thing with a using statement.
using (Font font2 = new Font("Arial", 10.0f))
{
byte charset = font2.GdiCharSet;
}
</pre>
<blockquote style="border: none; font-family: Tahoma; margin: 0px 0px 0px 40px; orphans: 2; padding: 0px; text-align: -webkit-auto; widows: 2;">
<pre style="font-family: Consolas, Courier, monospace !important; font-size: 13px; line-height: 17.5499992370605px; overflow: auto; padding: 5px; word-wrap: normal;"></pre>
</blockquote>
</div>
<br />
<br />
<br />
<h4>
Refactoring</h4>
Refactorings são saudáveis e devem ser feitos. Sempre que achar que um código pode ser melhorado quanto à legibilidade melhore-o. Sempre que algo pode ser feito de maneira mais rápida, mais fácil, mais elegante ou mais correta, refaça. Sempre que algo soar estranho, parecer "cheirar", troque. Use a regra do escoteiro e deixe o código mais limpo do que quando você encontrou.<br />
<br />
<br />
<h4>
Gambiarras</h4>
Toda gambiarra no código se volta contra você uma hora ou outra. Gambiarras causam infernos de manutenção, horas extras e expedientes de fim de semana.<br />
Toda gambiarra clama em alta voz por um refactoring. Um código ruim pode ter bad smells que são fruto de desconhecimento, limitações tecnológicas, cansaço ou erro humano, MAS gambiarras são sinais de relaxo, falta de ética e desorganização pessoal. O prazo não é desculpa para se fazer uma gambiarra. Se há uma forma mais elegante de se escrever um código procure melhorá-lo, mas se há uma forma definitivamente correta de se escrever um código, então use essa forma.<br />
<br />
<br />
<h4>
Excessões à regra </h4>
Widgets demasiadamente usados como Button e Textbox tem padrões de nomenclatura derivados da notação húngara fortemente entrincheiradas em nosso dia - a - dia, por isso são aceitáveis coisas como botões precedidos de btn (btnSalvar) e inputs precedidos de txt (txtNome). Isso está em conformidade com as práticas da Microsoft, pois os widgets de tela do office são todos prefixados. <br />
Variáveis de contadores de laço/iteradores podem ter um nome de uma letra só, como i,j,k,l,c. É mais inteligível desta forma, uma vez que os caracteriza como iteradores, além disso eles têm um escopo muito local, muito limitado. <br />
Em linguagens onde o nome da classe não pode ser igual ao nome do arquivo que a contém é comum, em PascalCase, prefixar as classes com T, mas apenas nesses casos. <br />
Em linguagens que não são case sensitive, como Delphi/Pascal/SQL, não é possível declarar um campo privado com camelCase e a propriedade que o acessa com o mesmo nome em PascalCase como abaixo:<br />
<br />
<pre class="brush:csharp">//Nào faça isso
private string nome;
public string Nome
{
get
{
return nome;
}
set
{
nome = value;
}
}
</pre>
Porém esse seria o nosso caso apenas usando SQL/Pascal/VB6. Usando C# isso não se aplica. Esse exemplo é trivial, mas o uso de _ ou de camelCase para os fields privados são os mais usados em C#.<br />
Nesses casos preceder o campo privado com F (PascalCase) em linguagens derivadas de pascal.<br />
<br />
<pre class="brush:csharp">//isso só é permitido em linguagens como Pascal ou Delphi. Não faça isso.
private string Fnome;
public string Nome
{
get
{
return Fnome;
}
set
{
Fnome = value;
}
}
</pre>
<br />
Como usaremos apenas C#, vamos prefixar campos de instancia locais com _, como geralmente é feito em linguagens derivadas de C.<br />
<br />
<pre class="brush:csharp">//Faça ISSO:
private string _nome;
public string Nome
{
get
{
return _nome;
}
set
{
_nome = value;
}
}
</pre>
<br />
<h4>
Faça:</h4>
<br />
<br />
<ul>
<li>Use PascalCasing para nomear classes, propriedades, métodos e Enuns</li>
<li>Use camelCasing para nomear variáveis locais, argumentos de métodos e de constructors</li>
<li>Use _camelCasing (camelCase precedido de _) para nomear campos privados</li>
<li>Se uma apreviação for fazer parte do nome de uma classe, propriedade ou constante, use PascalCase se ela tiver 3 letras ou mais. Ponha a abreviação em maiúsculas se ela tiver até 2 letras.</li>
<li>Use os nomes de tipos predefinidos da linguagem em vez dos System Types, exemplo: strung no lugar de String, int no lugar de Int32, bool no lugar de Boolean</li>
<li>Use variáveis implícitas para quando o tipo é óbvio ou não é importante, ou em laços for/foreach. Exemplo: var numero = Convert.ToInt32(Console.ReadLine());</li>
<li>Escreva um comando por linha</li>
<li>Escreva uma declaração por linha</li>
<li>Indente todas as linhas de continuação</li>
<li>Quebre uma linha para separar a definição de métodos da definição de propriedades</li>
<li>Prefira passar estruturas ou objetos DTO como parâmetros para um método do que listas grandes de parâmetros.</li>
<li>Prefira retornar objetos DTO ou estruturas com um propósito específico do que usar parâmetros ref ou out nos seus métodos.</li>
<li>Sempre que usar o operador "as " para typecasting seguro verifique se o retorno não é null. Se for null é porque o objeto não pode ser convertido para o tipo especificado.</li>
<li>Se você precisa comentar um bloco de código, considere usar refactoring para transformar esse bloco em um método, e de-lhe um nome conciso e apropriado. </li>
<li>Mantenha o tamanho de cada linha em até 130 caracteres (o suficiente para evitar rolagem horizontal)</li>
<li>Sempre envolva expressões booleanas de estrutura de repetição ou de decisão do tipo if, else, do, while, for e foreach com parênteses, mesmo que o compilador não exija.</li>
</ul>
<br />
<br />
<br />
<br />
<h4>
Não faça:</h4>
<br />
<br />
<ul>
<li>Não use notação húngara ou qualquer tipo de definição de tipo nos nomes de variáveis, isso é consistente com o .net framework, além disso o Visual Studio já te ajuda a determinar o tipo das variáveis.</li>
<li>Não use maiúsculas para nomear constantes, não é assim que é feito no .net. Maiúsculas atraem muito atenção.</li>
<li>Evite abreviações nos nomes de variáveis a não ser que sejam abreviações bem conhecidas como Id, XML, HTML</li>
<li>Não insira underscore _ no meio de identificadores, classes, constantes, propriedades e variáveis.</li>
<li>Não especifique o tipo de um enum a não ser que seja Flags ou bit fields</li>
<li>Não prefixe ou sufixe os nomes de Enum com a palavra "Enum"</li>
<li>Não comente código, ninguém saberá o que fazer com código comentado</li>
<li>Não use parâmetros de função como variáveis temporárias. O nome do parâmetro não reflete a intenção da variável.</li>
<li>Não use números em identificadores de campos ou métodos, como "Listar2". Isso geralmente é sinal de preguiça em encontrar um nome que revele propósito.</li>
<li>Não compare expressões booleanas com true ou false em if's. Perguntar if (variavel == true) ou if (variavel == false) prejudica a leitura e revela falta de conhecimento da estrutura if. Use if (variavel) ou if (!variavel).</li>
</ul>
<br />
<br />
<br />
<h4>
Lembre-se:</h4>
A qualidade de um código é medida pelo número de "que diabos ..." por segundo. <br />
A honestidade nas pequenas coisas não é uma coisa pequena.<br />
<br />
<br />
<b>Veja mais</b><br />
<a href="http://d8231s036n/bbi_cdn/download/CSharpCodingStandards.pdf" target="_blank">Lance Hunt C# Coding Standards</a><br />
<a href="http://d8231s036n/bbi_cdn/download/AvSol_Coding_Guidelines_for_CSharp.pdf" target="_blank">AvSol coding guidelines for C# 3.0-5.0</a><br />
<a href="http://d8231s036n/bbi_cdn/download/java_codeconventions_150003.pdf" target="_blank">Java code conventions</a><br />
<br />
<br />
<b>Livros</b><br />
<a href="http://www.livrariacultura.com.br/p/domain-driven-design-3252884">http://www.livrariacultura.com.br/p/domain-driven-design-3252884</a><br />
<a href="http://www.livrariacultura.com.br/p/extreme-programming-15065191">http://www.livrariacultura.com.br/p/extreme-programming-15065191</a><br />
<a href="http://www.livrariacultura.com.br/p/codigo-limpo-2874223">http://www.livrariacultura.com.br/p/codigo-limpo-2874223</a><br />
<br />
<br />
<b>Sites</b><br />
<a href="http://www.milfont.org/tech/2008/01/21/nao-use-notacao-estranha/">http://www.milfont.org/tech/2008/01/21/nao-use-notacao-estranha/</a><br />
<a href="http://www.macoratti.net/13/09/net_pcod1.htm">http://www.macoratti.net/13/09/net_pcod1.htm</a><br />
<br />
<br />
<b>Outras fontes</b><br />
Há vários padrões de codificação e outras boas práticas de programação. Abaixo exemplifico mais algumas fontes como referência / aprofundamento.<br />
Há também padrões de codificação para linguagens específicas, elaborados pelas empresas que desenvolvem esses produtos ou pela comunidade de programadores destas linguagens, como os padrões de PHP ou Java exemplificados em anexo.<br />
<a href="http://www.dofactory.com/reference/csharp-coding-standards">http://www.dofactory.com/reference/csharp-coding-standards</a><br />
<a href="https://csharpguidelines.codeplex.com/">https://csharpguidelines.codeplex.com/</a><br />
<a href="http://se.inf.ethz.ch/old/teaching/ss2007/251-0290-00/project/CSharpCodingStandards.pdf">http://se.inf.ethz.ch/old/teaching/ss2007/251-0290-00/project/CSharpCodingStandards.pdf</a><br />
<a href="https://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.100).aspx</a><br />
<br />
<br />
<br />
<br />
<br />
<br /></div>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com1tag:blogger.com,1999:blog-120161195353369613.post-84795491889558900972015-02-16T11:17:00.001-02:002015-02-16T11:18:33.626-02:00Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel - TrobleshootingIf you get <br />
<h2 style="background-color: white; color: maroon; font-family: Verdana; font-size: 14pt; font-weight: normal;">
<i>Could not load type System.ServiceModel.Activation.HttpModule from assembly System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.</i></h2>
<div>
<br /></div>
<div>
error trying to access a webservice in .net framework 4.0 or 4.5 it is caused by a conflict between 3.0 and 4.0 version.</div>
<div>
<br /></div>
<div>
Fortunately you can fix it in a per application basis. You have only to go to IIS Manager, select your application, double click in modules and delete ServiceModel version 3.0 module. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-eIYIH2ZjNBE/VOHp6Y0qNtI/AAAAAAAABWY/44rp20tZT8Y/s1600/modulos.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-eIYIH2ZjNBE/VOHp6Y0qNtI/AAAAAAAABWY/44rp20tZT8Y/s1600/modulos.png" height="298" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-EukErCxJ1jI/VOHrM934HyI/AAAAAAAABWk/uVPTF5DAdgw/s1600/servicemodel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-EukErCxJ1jI/VOHrM934HyI/AAAAAAAABWk/uVPTF5DAdgw/s1600/servicemodel.png" height="298" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
</div>
<div>
If you need version 3.0 again or delete 4.0 accidentally you can fix it adding the module again, using the strings below to register the asemblies.</div>
<div>
<br /></div>
<div>
ServiceModel - System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089<br />
<br />
ServiceModel-4.0 - System.ServiceModel.Activation.ServiceHttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35<br />
<br />
Enjoy :)</div>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-53141784914851120022015-02-16T11:06:00.003-02:002015-02-16T11:06:56.202-02:00Não foi possível carregar o tipo System.ServiceModel.Activation.HttpModule do assembly System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. Como Resolver.Como resolver o erro:<br />
<h2 style="background-color: white; color: maroon; font-family: Verdana; font-size: 14pt; font-weight: normal;">
<i>Não foi possível carregar o tipo System.ServiceModel.Activation.HttpModule do assembly System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.</i></h2>
<div>
<i><br /></i></div>
Alguns recursos / módulos e assemblies do .net causam conflitos entre as versões. Esses conflitos são causados pelo IIS, que "Não sabe" qual a versão correta do assembly carregar, mesmo se o application pool está configurado com a versão correta.<br />
<br />
Felizmente essas configurações podem ser corrigidas em cada application no IIS.<br />
<br />
Esse erro especificamente é causado por um conflito entre as versões 3.0 e 4.0 do assembly ServiceModel.<br />
<br />
Se sua aplicação é em .net 4.0 ou 4.5 e você obteve este erro ao tentar abrir um webservice vá ao IIS (Painel de controle / Ferramentas Administrativas / Gerenciador do Serviços de Informações da Internet (IIS) ), abra o seu site, de um duplo clique em módulos.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-eIYIH2ZjNBE/VOHp6Y0qNtI/AAAAAAAABWY/44rp20tZT8Y/s1600/modulos.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-eIYIH2ZjNBE/VOHp6Y0qNtI/AAAAAAAABWY/44rp20tZT8Y/s1600/modulos.png" height="297" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Delete o módulo ServiceModel, deixando apenas o ServiceModel-4.0.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-EukErCxJ1jI/VOHrM934HyI/AAAAAAAABWk/uVPTF5DAdgw/s1600/servicemodel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-EukErCxJ1jI/VOHrM934HyI/AAAAAAAABWk/uVPTF5DAdgw/s1600/servicemodel.png" height="298" width="400" /></a></div>
<br />
<br />
Caso você necessite dele novamente, ou tenha apagado o 4.0 por engano, abaixo encontram-se as strings para registrar os assemblies.<br />
<br />
System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089<br />
<br />
<br />
Espero ter ajudado.<br />
<br />
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com3tag:blogger.com,1999:blog-120161195353369613.post-69344439166277027432015-02-02T01:44:00.002-02:002015-02-02T01:46:47.107-02:00Detectar o encoding de um arquivo para não corromper ao transformá-loEm uma certa aplicação que eu fiz, um programa windows forms deveria fazer upload de um arquivo CSV para uma aplicação WEB para a importação do arquivo.<br />
<br />
O problema é que esse sistema funcionava em 8 línguas diferentes, então, obviamente, o sistema deveria suportar vários tipos de caracteres (e encodings) diferentes.<br />
<br />
Além disso o CSV era ou montado por um usuário, exportando do excel, ou exportado por um ERP.<br />
<br />
Seria impossível impor ao usuário que sempre gerasse um arquivo UTF-8, porque além de não ser obrigado a saber o que é isso, sistemas ERP legados dificilmente exportarão os arquivos nesse formato, e você, em uma empresa pequena, simplesmente não têm como impor que uma empresa como SAP ou Totvs altere seus sistemas para exportar arquivos em UTF-8.<br />
<br />
O site da web aceitava o arquivo como vinha, fazia uma conversão forçada para o formato padrão (ANSI ISO 8859-1) e importava o arquivo.<br />
<br />
Conversões forçadas são aquelas que você faz sem saber qual é o formato de origem do arquivo.<br />
Se você simplesmente mandar abrir um arquivo do qual não sabe o encoding o .net framework usará o encoding default do computador. Se o arquivo não estiver na codificação padrão ele será lido erroneamente, parecendo estar corrompido. Qualquer operação com ele, como concatenar informações e escrever em outro arquivo resultará em strings corrompidas, com acentos perdidos.<br />
<br />
Se o arquivo for ASCII ou o ANSI no encoding padrão de um computador com windows em inglês ou português a conversão ocorreria sem problemas. Se o arquivo fosse UTF-8 ou qualquer outro codepage ou tivesse caracteres especiais de uma outra linguagem essa conversão forçada corromperia o arquivo.<br />
<br />
Como se isso não bastasse, havia um outro fator: ao subir o arquivo direto pelo site o browser identificava o encoding do arquivo e colocava o encoding correto no cabeçalho. Ao ler o stream e colocar o resultado em uma string o .net fazia uma conversão "não forçada" para o formato padrão do servidor, pois ele sabia o formato de origem, informado pelo request, e esse tipo de conversão muda o formato e o encoding de um arquivo sem corromper, mantendo os mesmos caracteres especiais e acentuados, apenas com uma outra codificação.<br />
<br />
Isso mascarava o problema, pois raramente ocorria uma corrupção de arquivo.<br />
<br />
Por outro lado, quando eu tentava fazer o upload com a aplicação windows, eu tentava impor ou assumir um determinado formato e fazer o upload nesse formato. Um pré processamento era realizado antes do upload do arquivo.<br />
<br />
Eu precisava que minha aplicação windows detectasse qual era o encoding do arquivo antes de abri-lo, fizesse as operações necessárias, colocasse esse encoding no cabeçalho http do request e fizesse o upload desse arquivo. O servidor, por sua vez, deveria também detectar o encoding do arquivo, fazer uma asserção para comparar com o encoding informado no request e lançar uma exceção se fossem diferentes. Se fossem iguais ele poderia prosseguir com o processamento do arquivo.<br />
<br />
Como se faz para detectar o encoding de um arquivo. Como o browser faz isso?<br />
<br />
Uma pesquisada no google me fez encontrar a biblioteca <a href="http://code.google.com/p/chardetsharp/" target="_blank">chardet </a><br />
<br />
Foi necessária a instalação do <a href="http://tortoisesvn.net/downloads.html" target="_blank">TortoiseSVN </a> para baixar o source da mesma, que está no google code. Recompilei o source, e nesse post eu disponibilizo tanto o source como o compilado para download.<br />
<br />
Essa biblioteca se propõe a analisar n bytes de um arquivo de texto e fazer uma heurística para descobrir que tipo de encoding ele usa, baseando-se em uma estatística dos caracteres encontrados.<br />
<br />
Instale o tortoise SVN, clique com o direito na área de trabalho, dê o comando tortoise checkout e coloque o endereço <strong style="background-color: #e5ecf9; font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; font-size: 12px;"><em>http</em></strong><span style="background-color: #e5ecf9; font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; font-size: 12px;">://chardetsharp.googlecode.com/svn/trunk/</span> conforme a figura abaixo.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-19jfBeB-Wbc/VM0lpSETyzI/AAAAAAAABV0/UQeZgCz8jmQ/s1600/chardet_svn.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-19jfBeB-Wbc/VM0lpSETyzI/AAAAAAAABV0/UQeZgCz8jmQ/s1600/chardet_svn.png" height="261" width="320" /></a></div>
<br />
Abra o sln com o visual studio e recompile o mesmo. Agora você pode importar a dll gerada no seu projeto.<br />
<br />
Também encontrei a classe <a href="http://www.codeproject.com/Articles/17201/Detect-Encoding-for-In-and-Outgoing-Text" target="_blank">EncodingTools</a> no site do code project, que fazia uso de um outro algoritmo para identificar o encoding. Essa classe, podemos dizer, é mais "caseira".<br />
<br />
Encontrei uma classe chamada <a href="https://gist.github.com/TaoK/945127" target="_blank">TextFileEncodingDetector no git</a> que não é muito boa, pois se baseia apenas na detecção do BOM (byte order mark) coisa que a Unicode já descontinuou. <a href="http://unicode.org/faq/utf_bom.html" target="_blank">Mais sobre Unicode e BOM.</a><br />
<br />
Por último eu encontrei uma biblioteca chamada <a href="http://code.google.com/p/ude/" target="_blank">UDE</a> que na minha opinião foi a mais completa e profissional. Tanto a chardet como a UDE são ports do <a href="http://mxr.mozilla.org/mozilla/source/extensions/universalchardet/" target="_blank">Mozilla Universal Character Detector</a> no entanto a UDE está mais atual. É a biblioteca usada pela mozilla para detecção de caracteres. A UDE também deve ser baixada com o SVN no endereço e recompilada. No arquivo ao final desse post você pode ver todo<br />
<br />
Precisava testar essas três bibliotecas tanto com arquivos de teste como com meus arquivos de produção para saber qual trabalhava melhor. Para testar em casos extremos usei tanto arquivos muito pequenos, com caracteres especiais mas sem caracteres suficientes para caracterizar um determinado encoding / linguagem, e testei com arquivos grandes todos em ANSI e que tinham um único caractere em utf-8.<br />
<br />
Eu criei uma classe estática com uma única função para facilitar a transformação de um arquivo em um vetor de bytes. Como meus arquivos são pequenos não fiz nenhuma consideração quanto à performance ou quanto à limitar o tamanho do vetor de bytes. Se você for importar arquivos maiores do que 10mb seria prudente levar isso em consideração.<br />
<br />
<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace EncodeDetector
{
public static class TextUtils
{
public static byte[] FileToBytes(string filename)
{
using(FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
byte[] queEuGosto = new byte[fs.Length];
fs.Read(queEuGosto, 0, (int)fs.Length);
return queEuGosto;
}
}
}
}
</pre>
Também criei uma classe chamada VtrEncodingDetector como um wrapper para a biblioteca UDE, com dois objetivos: primeiro, se for detectado que o arquivo tem um BOM, então eu posso identificar o tipo do arquivo lendo apenas 3 ou 4 bytes em vez do arquivo todo. (isso não é confiável, pois o arquivo pode ter uma BOM marcando UTF-8 e estar todo em ANSI). Outro motivo é que eu posso trocar a implementação interna da minha biblioteca assim que eu encontre uma biblioteca de detecção de charset que eu goste mais.<br />
Abaixo o código da classe.<br />
<br />
<br />
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mozilla.CharDet;
using Ude;
namespace EncodeDetector
{
public static class VtrEncodingDetector
{
/// <summary>
/// Retorna encoding do streaming. (UTF7; UTF8; Unicode)
/// </summary>
/// <param name="stream" />Bytes do Arquivo
/// <returns>Encoding Type</returns>
public static Encoding GetEncodingFile(byte[] bytes)
{
if (bytes != null && bytes.Length >= 2)
{
//verifica esses primeiro pois utf32 pode confundir-se com utf16
if (bytes[0] == 0xff && bytes[1] == 0xfe && bytes[2] == 0 && bytes[3] == 0)
return Encoding.UTF32;
//utf-32BE Unicode (UTF-32 Big-Endian)
if (bytes[0] == 0 && bytes[1] == 0 && bytes[2] == 0xfe && bytes[3] == 0xff)
return Encoding.GetEncoding(12001);
if (bytes[0] == 255 && bytes[1] == 254)
return Encoding.Unicode;
if (bytes[0] == 0xfe && bytes[1] == 0xff)
return Encoding.BigEndianUnicode;
if (bytes[0] == 239 && bytes[1] == 187 && bytes[2] == 191)
return Encoding.UTF8;
if (bytes[0] == 60 && bytes[1] == 63)
return Encoding.ASCII;
//reconhecimento de utf7 http://pt.wikipedia.org/wiki/Marca_de_ordem_de_byte
if (bytes[0] == 43 && bytes[1] == 47 && bytes[2] == 118 && (bytes[3] == 56 || bytes[3] == 57 || bytes[3] == 43 || bytes[3] == 47))
return Encoding.UTF7;
//uso da ferramenta UDE para detectar automaticamente o encoding
try
{
//http://code.google.com/p/ude/
CharsetDetector d = new CharsetDetector();
d.Feed(bytes, 0, bytes.Length);
d.DataEnd();
Encoding enc = Encoding.GetEncoding(d.Charset);
d.Reset();
if (enc != null)
return enc;
else
//por padrão retorna 1252, que é o iso 8859-1, ansi para europa ocidental, codepage padrão para windows em inglês e português
//http://msdn.microsoft.com/en-us/library/system.text.encoding.codepage(v=vs.110).aspx
//return Encoding.GetEncoding(1252);
return Encoding.Default;
}
catch
{
//por padrão retorna 1252, que é o iso 8859-1, ansi para europa ocidental, codepage padrão para windows em inglês e português
//http://msdn.microsoft.com/en-us/library/system.text.encoding.codepage(v=vs.110).aspx
//return Encoding.GetEncoding(1252);
return Encoding.Default;
}
}
//por padrão retorna 1252, que é o iso 8859-1, ansi para europa ocidental, codepage padrão para windows em inglês e português
//http://msdn.microsoft.com/en-us/library/system.text.encoding.codepage(v=vs.110).aspx
//return Encoding.GetEncoding(1252);
return Encoding.Default;
}
}
}
</pre>
<br />
Antes de começar os testes, abra o projeto do UDE. Você verá que na linha 71 do arquivo UniversalDetector.cs existe um field protected chamado charsetProbers. Um array de Probers.<br />
<pre class="brush:csharp">protected CharsetProber[] charsetProbers = new CharsetProber[PROBERS_NUM];
</pre>
<br />
<br />
Vá na classe CharsetDetector, arquivo CharsetDetector.cs, que é descendente de UniversalDetector e transforme esse field protegido em uma propertie somente leitura pública. Poderia ser um método Get também.<br />
<br />
<pre class="brush:csharp">public CharsetProber[] CharsetProbers { get { return this.charsetProbers; } }
</pre>
<br />
Isso fará com que a lista interna de CharsetProbers seja exposta, permitindo que você navegue por ela. Um prober é uma classe interna da biblioteca responsável por identificar um charset específico. Quando você cria a classe CharsetDetector e passa para ela um vetor de bytes para serem analisados ela cria vários probers para analisar o arquivo e nesse vetor ficam os probers usados, e a porcentagem de confiabilidade de cada um deles. Como existe um prober para cada encoding, o prober com maior confiabilidade será o que providenciará a resposta final da biblioteca.<br />
<br />
Em um projeto real essa modificação é totalmente desnecessária. Foi incluída aqui apenas de curiosidade, para nossos testes. Outra modificação é na biblioteca chardet. Ela sempre escreve o encoding detectado no console, mesmo que você não queira. É um processo interno de debug dela, mas atrapalha quando o teste é feito justamente em uma aplicação console. Você pode comentar a linha 255 do arquivo UniversalDetector.cs:<br />
//Console.Out.WriteLine(aCharset);<br />
<br />
Comente também a linha 197 do arquivo SingleByteCharsetProber.cs:<br />
//Console.Out.WriteLine(" SBCS: {0:0.000} [{1}]", GetConfidence(), CharSetName);<br />
<br />
Agora a biblioteca não vai mais fazer um dump do seu processo interno de detecção, mesmo em modo debug. A biblioteca UDE também tem essas saídas. Procure por console.writeline ou console.out.writeline dentro de todos os métodos DumpStatus e comente.<br />
<br />
E Finalmente a classe Program.cs onde faço os testes. Compile o programa e execute-o pela linha de comando, passando como argumento o nome de um dos arquivos da pasta data ou um que você tenha aí. Mandei junto com o exemplo um executável hexeditor.exe para que você veja como a codificação de um caractere acentuado pode mudar dependendo do encoding usado. Para debugar você pode colocar um nome de arquivo fixo, usar parâmetros da linha de comando, usar testes unitários ou usar um FileOpenDialog. Aproveite também os vários arquivos de testes que vêm com os testes unitários do UDE.<br />
<br />
<pre class="brush:csharp">//program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using href.Utils;
using KlerksSoft;
using Mozilla.CharDet;
using Ude;
namespace EncodeDetector
{
class Program
{
static void Main(string[] args)
{
if (args.Count() == 0)
{
Console.WriteLine("Informe um arquivo");
return;
}
//limpa o console
Console.Clear();
Console.WriteLine("Econding detectado para o arquivo: " + args[0]);
Console.WriteLine("");
//crio o vetor de bytes com o conteudo do arquivo
byte[] queEuGosto = TextUtils.FileToBytes(args[0]);
#region encoding tools
//Usando encoding tools
//fonte:http://www.codeproject.com/KB/recipes/DetectEncoding.aspx
Encoding enc1 = EncodingTools.DetectInputCodepage(queEuGosto);
if (enc1 != null)
Console.WriteLine("Encoding Tools\t-->\t" + enc1.EncodingName + "/" + enc1.BodyName + "/" + enc1.CodePage);
#endregion
#region TextFileEncodingDetector
//fonte: https://gist.github.com/TaoK/945127
Encoding enc2 = TextFileEncodingDetector.DetectTextByteArrayEncoding(queEuGosto);
if (enc2 != null)
Console.WriteLine("TextFileEncodingDetector\t-->\t" + enc2.EncodingName + "/" + enc2.BodyName + "/" + enc2.CodePage);
#endregion
#region chardet
//fonte: http://code.google.com/p/chardetsharp/
var d = new UniversalDetector();
d.HandleData(queEuGosto);
d.DataEnd();
Encoding enc3 = Encoding.GetEncoding( d.DetectedCharsetName);
if (enc3 != null)
Console.WriteLine("CharDet\t-->\t" + enc3.EncodingName + "/" + enc3.BodyName + "/" + enc3.CodePage);
#endregion
#region UDE via VtrEncodingDetector wrapper
//usando um wrapper para UDE
Encoding enc4 = VtrEncodingDetector.GetEncodingFile(queEuGosto);
if (enc4 != null)
Console.WriteLine("VtrEncodingDetector\t-->\t" + enc4.EncodingName + "/" + enc4.BodyName + "/" + enc4.CodePage);
#endregion
#region UDE direto
//uando UDE direto
//fonte: http://code.google.com/p/ude/
CharsetDetector cdet = new CharsetDetector();
cdet.Feed(queEuGosto, 0, queEuGosto.Length);
cdet.DataEnd();
Encoding enc5 = Encoding.GetEncoding(cdet.Charset);
if (enc5 != null)
{
Console.WriteLine("UDE\t-->\t" + enc5.EncodingName + "/" + enc5.BodyName + "/" + enc5.CodePage + " Com confiabilidade de " + (cdet.Confidence * 100).ToString("0.0") + "%");
foreach (var x in cdet.CharsetProbers)
{
if (x != null)
Console.WriteLine("\t- " + x.GetCharsetName() + "\t" + (x.GetConfidence() * 100).ToString("0.00"));
}
}
cdet.Reset();
#endregion
//só para podermos ver o resultado
//Console.ReadLine();
}
}
}
</pre>
<br />
No <a href="http://vitorrubio.com.br/downloads/EncodingDetector.7z">arquivo desse exemplo </a>enpacotei junto o source e a versão compilada da UDE e da chardet. Há também alguns arquivos de texto em encodings diferentes para teste.<br />
Divirta-se!Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com2tag:blogger.com,1999:blog-120161195353369613.post-24138302536995617472015-01-26T18:00:00.000-02:002015-02-01T23:36:06.828-02:00Programação orientada a objetos, mas afinal o que diabos é isso?Hoje eu programo orientado a objetos. Pelo menos eu "acho" isso. Conheci muita gente que dizia que programava orientado a objetos mas na verdade programava de maneira procedural, orientado a evento ou RAD.<br />
<br />
Não que as outras metodologias sejam ruins, mas é que muitas vezes elas são a ferramenta errada para se resolver o problema. Além disso muitos programadores misturam as metodologias combinando o pior das duas em vez de o melhor das duas.<br />
<br />
Já vi até programadores dizerem que programam orientado a objeto simplesmente porque a linguagem é orientada a objeto, ou pior ainda, porque a IDE tem "objetos" que você arrasta e solta em uma "form" e que você acessa funções (métodos) destes com seu nome e um ".".<br />
<br />
Meu amigo, isso é RAD e não POO. Embora RAD tenha o seu valor para prototipação e aplicações rápidas e sujas, não é um bom ambiente de desenvolvimento a longo prazo. É uma programação orientada a evento degenerada. Além disso, por mais que a linguagem e o framework de uma ferramenta RAD seja orientado a objetos, a literatura e a comunidade, geralmente, não é. Eles incentivam uma forma de programação "copia/cola componentes em uma tela" onde o "programador" geralmente não sabe lhufas do que está fazendo, se é que ele programa alguma linha. Esse tipo de programa tem uma manutenibilidade quase zero.<br />
<br />
Vide por exemplo o ambiente Delphi. É uma linguagem orientada a objeto com generics, interfaces, reflexão, sobrecarga de operadores e tudo o que uma linguagem orientada a objeto precisa ter. No entanto a comunidade Delphi é geralmente uma comunidade de "arrastadores de componentes" e "desenhistas de formulários". Não é culpa deles, a literatura disponível da ferramenta incentiva isso.<br />
<br />
Eu mesmo fui programador Delphi durante anos e ainda é uma linguagem muito querida para mim, mas eu aprendi a fazer as coisas um pouco diferente. A sugestão que eu dou? Aprenda uma outra linguagem, C# ou Java, para expandir os seus horizontes. Se optar por C#, faça as coisas "no braço" em vez de usar as ferramentas RAD. A longo prazo elas decepcionam.<br />
<br />
Por três vezes na minha carreira tive de fazer refactorings brutais em aplicações Delphi para possibilitar alguma expansividade em cima de um legado macarrônico, pois a manutenção era um inferno em vida.<br />
<br />
Daí, depois de ler inúmeros artigos e livros sobre POO, DDD, padrões de projeto e outras boas práticas de código verdadeiramente OO, me cai em uma avaliação para processo seletivo o que é POO.<br />
<br />
Eu nunca sei qual é a resposta que os avaliadores esperam com isso porque eu nunca sei o quanto eles sabem de POO ou se eles estão equivocados. Já trabalhei em empresas onde a "crença" local era que POO era herança. Em outra os funcionários e o dono acreditavam piamente que programavam orientado a objeto, quando na verdade era programação macarrônica com método faz tudo.<br />
<br />
A última empresa que trabalhei, um dos donos da empresa era, hummm, digamos, "programador", e ditava, ditatorialmente, as regras de como o código deveria ser desenvolvido: uma mistura de cobol não estruturado com asp, onde TODO o código do sistema estava no page_load das páginas.<br />
<br />
Aí vem em uma avaliação a pergunta sobre o que é POO, o que é herança, o que é polimorfismo etc ... Eu devo apenas definir? Explicar? Exemplificar?<br />
<br />
Compartilho abaixo o enunciado de uma dessas avaliações e as minhas respostas.<br />
<br />
<br />
<blockquote >
<b>Conceitos teóricos</b></blockquote>
<br />
<blockquote>
<b>1)<span style="font-size: 7pt; font-stretch: normal; font-weight: normal;">
</span></b><!--[endif]--><b>Qual
a importância da utilização da programação orientada a objetos? Cite algumas
técnicas.</b></blockquote>
<br />
<blockquote >
<b><o:p></o:p></b><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">R.: A programação orientada a objetos, associada à
outras boas práticas de programação, favorece um código mais coeso e menos
acoplado, facilitando o reaproveitamento de código e a manutenibilidade do
mesmo.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Na programação orientada a objetos, dados e ações
que pertencem a uma mesma entidade ou unidade lógica são agrupados em uma
classe, que é um tipo de objeto.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Uma classe pode ser instanciada, ou seja, ter um
objeto de seu tipo criado, e esse objeto conterá os dados da classe e as
operações que atuam sobre esses dados.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">A programação orientada a objeto, quando bem
aplicada, permite código menor, menos repetitivo e mais eficiente, por meio da
abstração.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Alguns conceitos importantes em POO são herança,
polimorfismo, abstração, compósição e agregação.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Herança permite que dados e comportamentos sejam
transmitidos de uma classe base para uma derivada sem que código seja
reescrito. Polimorfismo permite que haja diferentes implementações de um mesmo
método nos diferentes objetos que implementem uma mesma interface (ou tenham um
ancestral em comum). Por exemplo, ao ter
uma variável “a” da interface “i” diferente de nulo, quando executamos o método
“metodo()”, o código executado será o do objeto instanciado que implemente a
mesma assinatura de “metodo()”.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Composição é a ligação, através de construtores ou
setters, de vários objetos compondo um todo. O todo, nesse caso, é maior do que
as partes e não deve existir ou funcionar sem uma de suas partes. Com
composição se adiciona novos comportamentos a um objeto por adicionar mais
partes que interagem entre si.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Agregação é uma interação mais fraca que a
composição. Objetos e coleções de objetos podem ser ligados uns aos outros
criando um todo com comportamento próprio, mas as partes podem existir
separadamente.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Um exemplo de composição é um Carro e suas Rodas,
ou aproveitando o exemplo de e-commerce desse teste, o Pedido e seus itens.
Embora os produtos podem existir sem nunca serem comprados, um Pedido não
existe sem os itens, e um carro não tem propósito sem suas rodas.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Um exemplo de agregação seria um computador, pois
CPU e periféricos, embora trabalhem juntos também funcionam separadamente, e o
Carrinho e seus itens. Diferentemente do Pedido, um carrinho pode estar vazio,
no momento do começo das compras.</span></blockquote>
<br />
<br />
<blockquote >
<span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;"> </span><o:p> </o:p><o:p> </o:p><b>2)<span style="font-size: 7pt; font-stretch: normal; font-weight: normal;">
</span></b><!--[endif]--><b>Descreva
os princípios SOLID e porque eles são importantes.</b></blockquote>
<br />
<blockquote >
<b><o:p></o:p></b><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">R.: SOLID é uma abreviação de outras 5 abreviações.
Essas abreviações, em inglês são:</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">SRP (Single responsibility principle), significa que uma classe deve ter apenas uma
responsabilidade e por consequência disso apenas um motivo para
mudar.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">OCP (Open/Closed principle), significa que uma
classe deve ser fechada para modificação e aberta para extensão. Esse conceito
é uma extensão do conceito acima e quer dizer que uma classe não deve ser
modificada, mas deve ter seu comportamento extendido através de herança ou
composição.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">LSP (Liskov substitution principle) é o príncípio de substituição de liskov, que
significa que um objeto esperado pode ser substituido por qualquer objeto de
uma classe descendente. Quando uma classe filha altera o comportamento padrão
de um método ou omite uma propriedade, então o princípio de liskov está sendo
violado.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">ISP (Interface segregation principle) prega que de
devemo separar nossos objetos em várias interfaces, e que várias interfaces que
interagem e trocam mensagens entre si são melhores que um objeto único de
proposito geral. Isso permite flexibilidade e reaproveitamento de código
através de agregação e composição.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">DIP (dependency inversion principle) diz que um objeto não pode depender da
implementação concreta de outro, mas sim de sua interface. Esse princípio nos
guia, junto com o principio acima, a programar orientado a interfaces.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Por exemplo, se dois objetos executam a tarefa de
enviar um e-mail de confirmação, logo deveríamos ter um terceiro, responsável
pelo envio do e-mail. No entanto, se temos vários métodos ou bibliotecas de
envio de e-mail e não queremos que um objeto tenha uma dependência rígida com
uma implementação específica, então transformamos a classe de envio de e-mail
em uma classe de serviço, extraimos sua interface e, aos objetos que necessitam
de enviar um e-mail, entregamos uma variável do tipo dessa interfae, com um
objeto de envio de e-mail instanciado.</span></blockquote>
<br />
<br />
<blockquote >
<o:p> </o:p><b>3)<span style="font-size: 7pt; font-stretch: normal; font-weight: normal;">
</span></b><!--[endif]--><b>Cite
design patterns e para qual finalidade eles existem.</b></blockquote>
<br />
<blockquote >
<b><o:p></o:p></b><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">R.: </span><span style="color: #1f497d; mso-themecolor: text2;">São padrões de projeto. Um conjunto
de abstrações encontradas em vários projetos que se repetem, pois visam reslver
problemas específicos.<br /> <o:p></o:p></span><span style="color: #1f497d; mso-themecolor: text2;">No livro “Padrões de Projeto”, do grupo “Gang of Four”, existe um
catálogo de padrões de projeto identificados
e descritos por ele, como exemplos. Mas este livro não é a única fonte.
Há também o livro “Patterns of Enterprise Application Development” de Martin
Fowler.<br /> </span><span style="color: #1f497d; mso-themecolor: text2;">Dentre os padrões de projeto podemos citar os criacionais factory
method, que é um método que instancia um objeto inicializando-o e devolve-o
para o chamador, abstract factory, que é uma classe abstrata com factory
methods que, valendo-se de polimorfismo, delega a criação de objetos concretos
à suas própria implementações concretas, singleton, que cria uma instância de
um objeto e permite que apenas um seja criado. Podemos citar também o padrão
strategy, que permite que uma dentre várias ações diferentes possam ser escolhidas
dependendo do objeto instanciado e o padrão iterator, usado para se navegar em
uma coleção de objetos.</span><span style="color: #1f497d; mso-themecolor: text2;">Escrevi 4 artigos para a revista Clube Delphi sobre padrões de projeto,
3 sobre factory method e abstract factory e um sobre singleton, seguem links
abaixo:</span><span style="color: #1f497d; mso-themecolor: text2;"> </span><span style="color: #1f497d; mso-themecolor: text2;"><a href="http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_122#a-2883">http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_122#a-2883</a></span><span style="color: #1f497d; mso-themecolor: text2;"><a href="http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_123#a-2969">http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_123#a-2969</a></span><span style="color: #1f497d; mso-themecolor: text2;"><a href="http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_124#a-3081">http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_124#a-3081</a></span><span style="color: #1f497d; mso-themecolor: text2;"><a href="http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_133#a-3902">http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_133#a-3902</a></span><span style="color: #1f497d; mso-themecolor: text2;"> </span><span style="color: #1f497d; mso-themecolor: text2;">Design patterns não significam “Normas” de projeto, e sim “padrões” de
projeto. Padrões aqui no sentido matemático: uma forma que se repete.</span></blockquote>
<br />
<blockquote >
<span style="color: #1f497d; mso-themecolor: text2;"> </span><o:p> </o:p><o:p> </o:p><b>4)<span style="font-size: 7pt; font-stretch: normal; font-weight: normal;">
</span></b><!--[endif]--><b> Quais os principais conceitos que compõe o DDD.</b></blockquote>
<br />
<blockquote >
<b><o:p></o:p></b><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">R.: O principal conceito do DDD é o domínio, ou
seja, as regras de negócio. O foco do DDD é no domínio e as classes da camada
de negócio devem ser o core do sistema.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Como apoio a essa técnica DDD preconiza que o time
de desenvolvimento deve adotar o vocabulário, termo se jargões próprios do
domínio e criar um vocabulário padrão para toda a equipe.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">DDD desencoraja um desenvolvimento em um número
muit o grande de camadas (por exemplo usando WCF entre a camada de aplicação e
a GUI) porque o uso de DTO’s não é
natural à DDD. Nessa metodologia, tudo que foge ao negócio como glue code e
plumbing code, é considerado parte da infraestrutura. A esse conceito dá-se o
nome de linguagem ubíqua.<br /> </span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">Outros conceitos importantes em DDD é o conceito de
Entidade (objetos com ID e ciclo de vida, que são persistidos e têm existência
por si só) e sua distinção de objetos de valor (simples contêineres para
valores sem ciclo de vida ou identidade própria). Também são conceitos da DDD agregados,
serviços e repositórios.</span><span style="color: #365f91; mso-themecolor: accent1; mso-themeshade: 191;">DDD também é associado à outras boas práticas como
TDD e a separação do sistema em 4 camadas: Interface de usuário, Aplicação, Dominio
(entidades e objetos de valor ficam aqui) e Infra-estrutura (repositórios,
serviços e outras classes de apoio).</span></blockquote>
<br />
<br />
Será que me estendi demais? Tenho esse costume, e tenho o costume de fugir do assunto também, parece que minha mente não funciona muito linearmente, tampouco objetivamente. No entanto, o que você escreveria de memória, sem consultar seus livros anotações revistas e sites?Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-46731481403771557612015-01-26T12:00:00.000-02:002015-01-31T15:05:40.153-02:00Lista ligada em C#Um dos assuntos que estudamos em ciência da computação ou processamento de dados que eu mais gosto é: Algoritmos e Estrutura de Dados.<br />
<br />
Se bem que gostar não é garantia de dominar, né? É sempre um assunto meio complicado. Admiro muito os professores dessa matéria, que resolvem problemas desse tipo quase sem pensar.<br />
<br />
Uma das coisas que se estuda nessa matéria é a Lista Ligada. Trata-se de uma estrutura simples, porém poderosa, onde um atributo desta estrutura é um dado (de qualquer tipo que o programador queira) e um ponteiro para um próximo objeto de mesmo tipo. Se o ponteiro for null (em linguagens c-like, nil em pascal, nothing em basic) significa que não há próximo objeto.<br />
<br />
Abaixo a figura de um nó da lista.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-qIK_-O9lcz0/VMQPStDkYwI/AAAAAAAABUo/-qQIZpuJKuE/s1600/lista-ligada.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-qIK_-O9lcz0/VMQPStDkYwI/AAAAAAAABUo/-qQIZpuJKuE/s1600/lista-ligada.png" /></a></div>
<br />
Esses nós podem ser ligados uns aos outros em cadeias, conforme a figura abaixo.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-dhNsg526ChU/VMQQCemtVfI/AAAAAAAABUw/puwIQ2-vVBo/s1600/lista-ligada-normal.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-dhNsg526ChU/VMQQCemtVfI/AAAAAAAABUw/puwIQ2-vVBo/s1600/lista-ligada-normal.gif" height="90" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Além disso as listas podem ter dois ponteiros, um apontando para o elemento posterior e outro apontando para o anterior, formando uma lista duplamente ligada. A lista pode também ser circular, com o último elemento apontando para o primeiro. Nesses casos é comum termos um valor especial no "primeiro" nó para indicar que ele é a "cabeça" e assim não se navegar infinitamente pela lista. A cabeça também pode ser implementada com um ponteiro fora da lista circular apontando para um elemento qualquer da lista, sendo este o primeiro.<br />
<br />
Em linguagens sem suporte a OO isso é feito criando - se uma struct (ou record) onde um dos elementos é o tipo de dado requerido e o outro é um ponteiro para a própria estrutura. Nas linguagens OO todo objeto já é um ponteiro, a manipulação de referências torna-se transparente. Um nó nada mais é do que um objeto contendo uma propriedade de um determinado tipo e a outra propriedade do próprio tipo nó.<br />
<br />
Embora seja uma estrutura muito útil, se você trabalha com sistemas de informação você raramente usará listas ligadas no seu dia-a-dia, porque os frameworks e bibliotecas que usamos no nosso trabalho já tem tudo isso pronto, por isso podemos focar em regras de negócio e usabilidade, que é o que realmente é importante especificamente em nossa área.<br />
<br />
No entanto, periodicamente, aparecem problemas e exercícios envolvendo listas ligadas em avaliações de processos seletivos.<br />
<br />
Um processo seletivo pelo qual eu passei recentemente tinha a seguinte avaliação:<br />
<br />
<blockquote class="tr_bq">
<b>Exercício A - implementação de lista ligada</b><br />
Os objetivos desse exercício são:<br />
<ul>
<li>Parte 1 - implementar um sistema de lista-ligada</li>
<li>Parte 2 - realizar uma tarefa simples usando essa implementação</li>
</ul>
<i>Parte 1 - implementação da lista ligada</i><br />
Implemente um sistema de lista ligada integralmente de sua autoria. Não use as classes de<br />
Listas das suas bibliotecas<br />
Você decide se a solução vai envolver (uma ou mais) classes ou apenas funções; a<br />
implementação deve ser adequada (não excessiva) para a utilização que se fa rá dela (vide<br />
abaixo).</blockquote>
<br />
<blockquote class="tr_bq">
<i>Parte 2 - utilização da lista ligada</i><br />
Utilizando o sistema de lista ligada implementado na etapa anterior, escreva um programa que:<br />
<ul>
<li>crie duas listas ligadas: (por ex) Lista1 e Lista2</li>
<li>leia o arquivo texto entrada.txt e armazene suas linhas em Lista1</li>
<li>copie os elementos de Lista1 para Lista2 invertendo a sua ordem</li>
<li>grave os elementos de Lista2 no arquivo texto saida.txt</li>
</ul>
</blockquote>
<br />
Nada muito difícil, como pode ser visto, mas é o tipo de coisa que pode te pegar de surpresa porque você só viu na faculdade e, francamente, poucos de nós treinamos este tipo de algoritmo para estarmos sempre preparados.<br />
<br />
Minha resolução foi a seguinte: primeiro criei o nó.<br />
<br />
<pre class="brush:csharp"> /// <summary>
/// Classe Nó, um elemento da lista. Optei por torná-la genérica, assim ela pode carregar qualquer elemento em um nó.
/// </summary>
/// <typeparam name="T"></typeparam>
public class No<t>
{
public T valor { get; set; }
public No<t> proximo { get; set; }
}
</t></t></pre>
Note que criei a estrutura genérica assim um nó pode armazenar qualquer tipo de dado e tem uma propriedade, da classe No, que é o próximo nó genérico do mesmo tipo.<br />
Depois criei a função para ler o arquivo de entrada, conforme o código abaixo. Estas funções para manipulação da lista são métodos estáticos na própria classe Program de um console application que fiz.<br />
<br />
<br />
<pre class="brush:csharp"> /// <summary>
/// Carrega o arquivo definido no caminho e cria uma lista ligada na variavel n
/// </summary>
/// <param name="n" />
/// <param name="caminho" />
private static void CarregaArquivo(No<string> n, string caminho)
{
using (StreamReader sr = new StreamReader(caminho))
{
No<string> p = n;
string s = sr.ReadLine();
p.valor = s;
while (!sr.EndOfStream)
{
p.proximo = new No<string>();
s = sr.ReadLine();
p = p.proximo;
p.valor = s;
}
}
}
</string></string></string></pre>
Fiz um código estilo quick and dirty, obviamente esse código poderia ser otimizado. Ele poderia trazer a lista no seu retorno, atuando como factory method, assim eu não precisaria passar uma variável para ele inicializar por mim. Mas ele funciona. Ele pega a primeira linha do aquivo, joga no primeiro elemento e encadeia novos elementos conforme vai lendo as próximas linhas. Acredito não ser necessário explicar cada linha de código aqui, o .net framework fala por si :).<br />
<br />
Uma das coisas que o avaliador quer saber nesse tipo de exercício é se o candidato sabe recursividade. E para entender a recursividade você primeiro precisa saber a recursividade. Funções que se chamam a si mesmas, conceitos definidos em termos de si mesmos. Isso é recursividade. Você a vê a rodo na natureza e na matemática.<br />
Por isso as funções Imprime e Inverte eu criei recursiva. Na verdade é a melhor maneira de se trabalhar com estruturas de dados.<br />
Criei também uma Inverte iterativa (usando o laço while) porque me deparei com um desafio desses em uma outra avaliação para processo seletivo:<b> Inverta uma lista ligada sem usar recursividade</b>. Parece que o pessoal conhece "de cor" só a maneira recursiva. No dia achei difícil, estava nervoso, começo de carreira, e fui pego de surpresa. Hoje parece trivial.<br />
<br />
<br />
<pre class="brush:csharp"> /// <summary>
/// imprime o conteudo da lista ligada (partindo do nó n) na tela. Faz isso recursivamente.
/// </summary>
/// <param name="n" />
private static void Imprime(No<string> n)
{
if (n == null)
return;
Console.WriteLine(n.valor);
n = n.proximo;
Imprime(n);
}
/// <summary>
/// Inverte usando while
/// </summary>
/// <param name="n" />
/// <returns></returns>
private static No<string> InverteIterativa(No<string> n)
{
No<string> tmp;
No<string> corrente = n;
No<string> invertido = null;
while (corrente != null)
{
tmp = corrente.proximo;
corrente.proximo = invertido;
invertido = corrente;
corrente = tmp;
}
return invertido;
}
/// <summary>
/// inverte recursivamente
/// </summary>
/// <param name="n" />
/// <param name="invertida" />
private static void InverteRecursiva(No<string> n, ref No<string> invertida)
{
No<string> tmp;
No<string> corrente = n;
if (n == null)
return;
tmp = corrente.proximo;
corrente.proximo = invertida;
invertida = corrente;
corrente = tmp;
InverteRecursiva(corrente, ref invertida);
}
/// <summary>
/// salva a lista resultante no caminho especificado
/// </summary>
/// <param name="n" />
/// <param name="caminho" />
private static void Salva(No<string> n, string caminho)
{
using (StreamWriter sw = new StreamWriter(caminho))
{
No<string> corrente = n;
while (corrente != null)
{
sw.WriteLine(corrente.valor);
corrente = corrente.proximo;
}
}
}
</string></string></string></string></string></string></string></string></string></string></string></string></pre>
E a função main é esta: <br />
<br />
<br />
<pre class="brush:csharp"> static void Main(string[] args)
{
No<string> L1 = null;
No<string> L2 = null;
L1 = new No<string>();
CarregaArquivo(L1, @"c:\entrada.txt");
Console.WriteLine("Dados originais");
Imprime(L1);
L2 = InverteIterativa(L1);
//InverteRecursiva(L1, ref L2);
Console.WriteLine("Dados invertidos");
Imprime(L2);
Salva(L2, @"c:\saida.txt");
Console.ReadLine();
}
</string></string></string></pre>
Então é isso. Você pode<a href="http://www.vitorrubio.com.br/downloads/ListaLigada_V1.7z" target="_blank"> baixar aqui o código completo desse exercício de lista ligada</a>. Espero que te ajude nos seus estudos e nas suas entrevistas. Me deixe saber se tem algo errado com o código (sempre tem).
<br />
<br />
Uma versão alternativa da função de carregar arquivo seria assim:<br />
<br />
<br />
<pre class="brush:csharp"> private static No<string> CarregaAlternativo(string caminho)
{
No<string> result = new No<string>();
No<string> next = result;
using (StreamReader sr = new StreamReader(caminho))
{
string s = "";
while ((s = sr.ReadLine())!=null)
{
next.valor = s;
if (!sr.EndOfStream)
{
next.proximo = new No<string>();
next = next.proximo;
}
}
}
return result;
}
</string></string></string></string></string></pre>
<br />
<br />
Have fun :)Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-40262528533044795632015-01-25T12:00:00.000-02:002015-01-31T15:15:20.945-02:00Função para criar nova data em SQLO SQL 2012 e superior tem a função DATEFROMPARTS para criar uma nova data a partir dos inteiros Ano, Mes e Dia, mas as versões 2000, 2005 e 2008 como é que fica?<br />
<br />
Fica assim: você mesmo faz a função.<br />
<br />
<br />
<br />
<pre class="brush:sql">
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ############################################################################################################################################
-- # NOME : DATEFROMPARTS
-- # PRODUTO : SQL Server
-- # DEVELOPER : Vitor Luiz Rubio
-- # COPYRIGHT :
-- # OBJETIVO : Gerar uma data a partir dos seus componentes inteiros
-- # VERSAO : 1.0
-- # DT. CRIACAO : 2013-04-18
-- # DT. ALTERACAO :
-- #
-- # DEPENDENCIAS :
-- #
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2013-04-18 : Criação
-- #
-- ############################################################################################################################################
CREATE FUNCTION DATEFROMPARTS
(
@Year int,
@Month int,
@Day int
)
RETURNS datetime
AS
BEGIN
--data 0 é 1/1/1900
set @Year = @Year - 1900;
set @Month = @Month - 1;
set @Day = @Day - 1;
return dateadd(day, @Day, dateadd(month, @Month, dateadd(year, @Year, 0)))
--teste
--select dbo.DATEFROMPARTS(2013, 4, 18)
--select dbo.DATEFROMPARTS(2014, 1, 1)
--select dbo.DATEFROMPARTS(1983, 2, 14)
END
GO
</pre>
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-33807408582079383092015-01-24T22:28:00.000-02:002015-01-24T22:28:39.535-02:00Duas maneiras de listar as chaves estrangeiras de um banco de dadosAS vezes precisamos listar todas as chaves estrangeiras de um banco de dados (e as tabelas/campos referenciados pelas mesmas). Tanto para automação de nosso mecanismo de persistência como para documentação do banco de dados.<br />
<br />
Em algumas operações nós precisamos excluir todas as constraints, para fazer alguma manutenção ou inclusão desconsiderando-se a integridade referencial (geralmente ao passar dados de um banco para outro, cargas, restaurações etc), sendo estas recriadas depois.<br />
<br />
A consulta pelas chaves estrangeiras pode ser feita usando-se as tabelas de sistema sysobjects e syscolumns ou as views de sistema INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS e INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE.<br />
<br />
Usando sysobjects e syscolumns<br />
<br />
<pre class="brush:sql">
SELECT
o3.name 'Nome_Chave_Estrangeira',
o2.name 'Tabela',
sc1.name 'Coluna (FK)',
o1.name 'Tabela Referenciada',
sc2.name 'Coluna Referenciada (PK)'foreign key ('+sc1.name+') references '+o1.name+'('+sc2.name+')'
FROM
sysforeignkeys fk
INNER JOIN sysobjects o1 on o1.id = fk.rkeyid --para obter a cahve estrangeira e a tabela referenciada
INNER JOIN sysobjects o2 on o2.id = fk.fkeyid --tabla de objetos e campo da chave pk
inner join sysobjects o3 on o3.id = fk.constid --tabela de objetos e campo da constraint (constid) para pegar o nome da constraint
inner join syscolumns sc1 on sc1.id = fk.fkeyid and sc1.colid = fk.fkey --coluna pk
inner join syscolumns sc2 on sc2.id = fk.rkeyid and sc2.colid = fk.rkey --coluna referenciada fk
where
o1.name = 'company'
</pre>
<br />
Usando views de sistema.<br />
<br />
<pre class="brush:sql">
SELECT
rc.CONSTRAINT_NAME 'Nome_Chave_Estrangeira',
rcu.TABLE_NAME 'Tabela',
rcu.COLUMN_NAME 'Coluna (FK)',
rcu1.TABLE_NAME 'Tabela Referenciada',
rcu1.COLUMN_NAME 'Coluna Referenciada (PK)'
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
INNER JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu
ON rc.CONSTRAINT_CATALOG = rcu.CONSTRAINT_CATALOG
AND rc.CONSTRAINT_NAME = rcu.CONSTRAINT_NAME
INNER JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu1
ON rc.UNIQUE_CONSTRAINT_CATALOG = rcu1.CONSTRAINT_CATALOG
AND rc.UNIQUE_CONSTRAINT_NAME = rcu1.CONSTRAINT_NAME
where rcu1.TABLE_NAME = 'company'
</pre>
<br />
Podemos notar que usando as views de sistema nosso filtro é mais simples, mas usando sysobjects e syscolumns temos mais flexibilidade no que queremos trazer.<br />
<br />
Você pode fazer uma consulta gerar, como string/varchar, o código necessário para exclui todas as suas constraints, caso existam, e recriar todas elas, caso não existam, mas atenção: se alguma das suas constraints tiver políticas diferentes quanto ao "on update cascade" ou "on delete cascade" você simplesmente não pode excluí-las e recriá-las assim, em massa.<br />
<br />
<pre class="brush:sql">
SELECT
o3.name 'Nome_Chave_Estrangeira',
o2.name 'Tabela',
sc1.name 'Coluna (FK)',
o1.name 'Tabela Referenciada',
sc2.name 'Coluna Referenciada (PK)',
'IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'''+o3.name+''') AND parent_obj = OBJECT_ID(N'''+o2.name+''')) ALTER TABLE '+o2.name+' DROP CONSTRAINT ['+o3.name+']',
'IF not EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'''+o3.name+''') AND parent_obj = OBJECT_ID(N'''+o2.name+''')) ALTER TABLE '+o2.name+' add CONSTRAINT ['+o3.name+'] foreign key ('+sc1.name+') references '+o1.name+'('+sc2.name+')'
FROM
sysforeignkeys fk
INNER JOIN sysobjects o1 on o1.id = fk.rkeyid --para obter a cahve estrangeira e a tabela referenciada
INNER JOIN sysobjects o2 on o2.id = fk.fkeyid --tabla de objetos e campo da chave pk
inner join sysobjects o3 on o3.id = fk.constid --tabela de objetos e campo da constraint (constid) para pegar o nome da constraint
inner join syscolumns sc1 on sc1.id = fk.fkeyid and sc1.colid = fk.fkey --coluna pk
inner join syscolumns sc2 on sc2.id = fk.rkeyid and sc2.colid = fk.rkey --coluna referenciada fk
where
o1.name = 'company'
</pre>
<br />
<br />
Esse link foi de grande ajuda para <a href="http://www.mssqltips.com/sqlservertip/1151/identify-all-of-your-foreign-keys-in-a-sql-server-database/" target="_blank">identificar todas as chaves estrangeiras de uma tabela</a><br />
<br />
Have Fun :)Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-73239295939682246182014-10-23T19:03:00.004-02:002014-10-23T19:03:47.831-02:00Fácil e reutilizável galeria de imagens em Jquery Se você é programador vai achar esse código um tanto quanto é trivial, mas se você for designer, como o cara que me pediu isso, talvez isso seja muito útil pra você.<br />
<div>
<br /></div>
<div>
Direto vemos galerias de imagens e hotsites e afins, e hoje é simplesmente ridículo fazer esse tipo de coisa com flash. Flash aos poucos está sendo banido da Internet. </div>
<div>
<br /></div>
<div>
HTML5 e um pouco de jQuery é o que você precisa para fazer uma galeria de imagens onde seja possível escolher a imagem com thumbnails, avançar, voltar e ter exibição automática em ciclo. </div>
<div>
<br /></div>
<div>
Aqui eu corrijo um erro muito comum dessas galerias: se uma nova imagem aparece a cada 5 segundos, e o usuário passou 4 segundos na última imagem, não seria correto trocar a imagem novamente no timeout, um segundo depois. Com a interação do usuário o timer deveria ser resetado. </div>
<div>
<br /></div>
<div>
Crie uma página HTML com o conteúdo abaixo. Você pode trazer o jquery de um CDN também.<br />
<br />
Repare nos comentários do código. Uso atributos do tipo data-* e algumas funções anônimas.</div>
<pre class=brush:html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
.conteudo{
width:300px; height:300px;
background:url(img/712.GIF) center 150px no-repeat;
}
</style>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript">
//cria um vetor com todas as imagens, assim este é o único lugar que deve ser alterado.
//o vetor é uma lista de objetos JSON com as propriedades thumbnail e grande, e pode vir de uma requisição ajax
var todasImagens = [
{thumbnail:"img/001.gif", grande:"img/grande001.gif"},
{thumbnail:"img/002.gif", grande:"img/grande002.gif"},
{thumbnail:"img/003.gif", grande:"img/grande003.gif"}
];
//define a posição atual, a primeira e a última baseada no tamanho do aray acima
var atual = 0;
var minimo = 0;
var maximo = todasImagens.length-1;
$(document).ready(function(){
//objeto intervalo, marca o tempo de mudança de imagem automática
var intervalo = null;
//inicialização
//função que troca a imagem
var trocaImagem = function()
{
//primeiro verifica se a imagem mostrando é diferente do vetor no índice atual (se for diferente então mudou)
if($('#imagemzona').attr('src') != todasImagens[atual].grande)
{
//sempre limpa o intervalo antes de mudar a imagem ...
clearInterval(intervalo);
$('#imagemzona').hide();
$('#imagemzona').attr('src', todasImagens[atual].grande);
$('#imagemzona').fadeIn();
//... e redefine depois, assim a imagem não salta automaticamente apos o usuário ter avançado manualmente
defineIntervalo();
}
};
//avança a imagem. Se atual passar do máximo, volta para o mínimo e completa uma volta
var avancarImagem = function()
{
atual++;
if(atual > maximo)
atual = minimo;
trocaImagem();
};
//retrocede a imagem. Se passar do mínimo pula pra última, fazendo um ciclo ao contrário
var retrocederImagem = function()
{
atual--;
if(atual < minimo)
atual = maximo;
trocaImagem();
};
//define o intervalo ao iniciar ...
var defineIntervalo = function()
{
//e o intervalo definido com setInterval nos diz que a função avancarImagem será executada a cada 5 segundos (5000 milissegundos)
intervalo = setInterval(avancarImagem, 5000);
};
//execução
//inicia o contador de tempo
defineIntervalo();
//coloca a primeira imagem
trocaImagem();
//cria thumbnails clicáveis
//repare no uso do atributo data-idx. é um índice armazenado no img do thumbnail. Esse índice é usado no vetor todasImagens
$.each(todasImagens, function(idx, value){
$('#legenda').append('<img class="thumb" width=50 height=50 data-idx="'+idx.toString()+'" src="'+ value.thumbnail +'" />');
});
//se clicado em um thumbnail obtem o atributo data-idx ...
$('.thumb').click(function(){
atual = parseInt($(this).data("idx")); //data-idx, mesma coisa que .attr("data-idx")
trocaImagem(); //... e troca a imagem
});
//avança se clica no avançar
$("#avancar").click(avancarImagem);
//volta se clica no voltar
$("#voltar").click(retrocederImagem);
});
</script>
</head>
<body>
<div id="legenda"></div>
<br>
<div class="conteudo">
<img src='img/001.gif' id='imagemzona' width=300 height=300/>
</div>
<br>
<br>
<p><a id="voltar" href="#">«</a> <a id="avancar" href="#">»</a></p>
</body>
</html>
</pre>
<div>
<a href="http://vitorrubio.com.br/downlaods/Galeria-jquery.7z" target="_blank">Baixe o Exemplo</a></div>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-75965802189280486312014-10-23T16:32:00.001-02:002014-10-23T16:34:47.912-02:00Tudo o que você precisa saber sobre CORSPrimeiro de tudo, a documentação: <a href="http://www.w3.org/TR/cors/">http://www.w3.org/TR/cors/</a><br />
Segundo, como configurar no IIS 7: <a href="http://i-liger.com/article/cross-domain-http-request">http://i-liger.com/article/cross-domain-http-request</a><br />
Como configurar cors no IIS 6: <a href="http://enable-cors.org/server_iis6.html">http://enable-cors.org/server_iis6.html</a><br />
É importante salientar que essa configuração também é possível via web.config. Como o web.config é hierárquico, hereditário e combinatório, então você pode colocar um web.config adicional pequenininho com cabeçalhos só para permitir CORS nas páginas de um diretório, em vez da aplicação inteira.<br />
Se a configuração não for para a aplicação inteira nem para uma pasta inteira temos que colcoar cabeçalhos http na página. Os cabeçalhos são:<br />
<ul>
<li>Access-Control-Allow-Origin -> indica quais domínios podem fazer um request no seu, colocando * permite todos os domínios.</li>
<li>Access-Control-Allow-Methods -> indica quais métodos são permitidos o cliente consultar no seu domínio. Não adianta colocar só post ou get, pois o client pode mandar uma requisição head para saber encoding e contenttype antes, ou uma requisição options, para saber mais configurações (é o browser / javascript que manda esses métodos), portanto, permita GET, POST, PUT, DELETE, HEAD, DEBUG, OPTIONS</li>
<li>Access-Control-Allow-Headers -> indica quais headers o client pode solicitar, configurar Content-Type, Accept</li>
<li>Access-Control-Max-Age -> indica quantos segundos um request já atendido deveria ser mantido em cache. Muita gente coloca 1728000, mas eu acho isso muito tempo. 72000 (20 horas) é um número muito mais aceitável, considerando que mesmo um conteúdo estático como o de um e-learning pode mudar de um dia para o outro.</li>
</ul>
Um exemplo de web.config para um único diretório é:<br />
<pre class="brush:xml"><configuration>
<system .webserver="">
<httpprotocol>
<customheaders>
<add name="Access-Control-Allow-Origin" value="*">
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept">
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, HEAD, DEBUG, OPTIONS">
<add name="Access-Control-Max-Age" value="72000">
</add></add></add></add></customheaders>
</httpprotocol>
</system>
</configuration>
</pre>
Também é possível fazer isso em uma única página, colocando, como primeiro código a ser executado no page_load, o código<br />
<pre class="brush:c#">HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, HEAD, DEBUG, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "72000");
</pre>
As configurações no IIS valem para todas as páginas, enquanto que as configurações via web.config são para um diretório e o código acima para uma única página. Todos eles representam a mesma configuração.<br />
Mais informações e exemplos: <a href="http://encosia.com/using-cors-to-access-asp-net-services-across-domains/">http://encosia.com/using-cors-to-access-asp-net-services-across-domains/</a>Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-44765028818538423032014-10-17T15:36:00.003-03:002014-10-17T15:36:33.246-03:00Domine a herança de construtoresEm hierarquias longas de objetos é importante saber onde colocar o código dos contructors (construtores) pois eles tem uma ordem lógica para executar e, se for um parameterless constructor (construtor sem parâmetros) então todos os parameterless constructors serão executados desde a raiz object.<br />
<br />
Um parameterless constructor sempre executa o parameterless constructor da classe base (pai), mas um construtor com parâmetros você deve especificar:<br />
<br />
<br />
<ol>
<li>:this([parametros]) para executar um outro constructor na mesma classe e deixar a hierarquia seguir sucessivamente</li>
<li>:base([parametros]) para executar um constructor específico da classe base</li>
<li>NADA para executar o parameterless constructor da base.</li>
</ol>
<br />
<br />
O <A HREF="http://www.vitorrubio.com.br/downloads/HerancaConstrutor.7z">programa abaixo</A> ilustra isso.<br />
<br />
<br />
<pre class="brush:c#">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HerancaConstrutor
{
class ClasseBase
{
public ClasseBase()
{
Console.WriteLine("parameterless constructor da classe ClasseBase");
}
}
class DerivadaSemConstructor : ClasseBase
{
}
class DerivadaComConstructor : ClasseBase
{
public DerivadaComConstructor()
{
Console.WriteLine("parameterless constructor da classe DerivadaComConstructor");
}
public DerivadaComConstructor(string argumento)
{
Console.WriteLine("constructor com argumentos da classe DerivadaComConstructor. Argumento: " + argumento);
}
}
class DerivadaDaDerivadaSemConstructor : DerivadaSemConstructor
{
}
class DerivadaDaDerivadaComConstructor : DerivadaComConstructor
{
public DerivadaDaDerivadaComConstructor()
: base("")
{
Console.WriteLine("parameterless constructor da classe DerivadaDaDerivadaComConstructor");
}
public DerivadaDaDerivadaComConstructor(string argumento) : base(argumento)
{
Console.WriteLine("constructor com argumentos da classe DerivadaDaDerivadaComConstructor. Argumento: " + argumento);
}
}
class Program
{
static void Main(string[] args)
{
var v1 = new ClasseBase();
var v2 = new DerivadaSemConstructor();
var v3 = new DerivadaComConstructor();
var v3b = new DerivadaComConstructor("b");
var v4 = new DerivadaDaDerivadaSemConstructor();
var v5 = new DerivadaDaDerivadaComConstructor();
var v5b = new DerivadaDaDerivadaComConstructor("b");
}
}
}
</pre>
<br />
<br />
Toda classe sem parameterless constructor padrão possui um parameterless constructor implícito herdado de object.<br />
Toda classe com um parameterless constructor implicitamente executa o parameterless constructor da classe base, estando ele sendo chamado com :base() explicitamente ou não. <br />
<br />
Se um constructor não é criado eecuta o parameterless constructor da classe base<br />
se um constructor é criado mas não é definido um constructor base é executado o parameterless constructor da base.<br />
se um construtor é criado e é especificado um outro construtor da classe base com argumentos para ser executado, é executado o constructor escolhido e o constructor da classe ancestral da base é executado.<br />
Se um constructor chama outros constructors, com ou sem parâmetros, na classe atual ou na classe base, não importa, uma hora um constructor parameterless implícito ou explícito será executado.<br />
<div>
<br /></div>Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-902163414352760552014-10-17T15:30:00.000-03:002014-10-17T15:37:03.298-03:00As vezes eu esqueço por que programo<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-FDTVNeg8ufU/VEA7GbiquuI/AAAAAAAABRE/eLq_M1K8XZ4/s1600/a9MEMKK_460s_v1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-FDTVNeg8ufU/VEA7GbiquuI/AAAAAAAABRE/eLq_M1K8XZ4/s1600/a9MEMKK_460s_v1.jpg" /></a></div>
<br />
<br />
<br />
Mas o <a href="http://9gag.com/" target="_blank">9gag </a>me faz o favor de me lembrar.<br />
<br />
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0São Paulo - SP, República Federativa do Brasil-23.5505199 -46.633309399999973-23.5505199 -46.633309399999973 -23.5505199 -46.633309399999973tag:blogger.com,1999:blog-120161195353369613.post-25047631386974129132014-10-16T18:24:00.000-03:002014-10-16T18:24:18.756-03:00Duas funções úteis para manipulação de datas<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-s5UonnjYZsc/VEA3d0sp5hI/AAAAAAAABQ4/IeKlh2ZIORI/s1600/calendar-151572_640.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-s5UonnjYZsc/VEA3d0sp5hI/AAAAAAAABQ4/IeKlh2ZIORI/s1600/calendar-151572_640.png" height="320" width="320" /></a></div>
De tempos em tempos precisamos fazer aquele processamento que só pode ser feito em dias úteis. Seja a data de pagamento de um boleto, o agendamento de uma entrevista e assim por diante.<br />
<br />
O desafio disso está no fato de que temos feriados nacionais com dia fixo, feriados com dia variável porém computável (através de algoritmos) e feriados municipais.<br />
<br />
Os municipais não tem outra forma de atender senão consultando uma tabela do banco de dados pelo código do município, mas os feriados nacionais fixos nós podemos dar uma bom começo.<br />
<br />
Segue abaixo a função fn_dia_util que retorna 1 se o dia for útil e 0 se for sábado, domingo ou feriado (usando a função weekday para isso) e a função fn_proximo_dia_util, que verifica se o próximo dia é util e se não for vai acrescentando um em loop. Mesmo se o feriado cair numa sexta-feira ela retornará o próximo dia útil.<br />
<br />
<br />
<pre class="brush: sql">-- ############################################################################################################################################
-- # NOME : fn_dia_util
-- # PRODUTO : blog.vitorrubio.com.br
-- # DEVELOPER : Vitor Luiz Rubio
-- # COPYRIGHT :
-- # OBJETIVO : Dada uma data, diz se é dia útil (1) ou não (0)
-- # VERSAO : 1.0
-- # DT. CRIACAO : 2014-10-16
-- # DT. ALTERACAO :
-- #
-- # DEPENDENCIAS :
-- #
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2014-10-16 : Criação
-- #
-- ############################################################################################################################################
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION dbo.fn_dia_util
(
@data datetime
)
RETURNS integer
AS
BEGIN
declare @result integer
if (
--VERIFICA SE É SÁBADO OU DOMINGO
(datepart(weekday, @data) IN (1,7)) or
--VERIFICA SE É ALGUM FERIADO NACIONAL DE DIA FIXO
(convert(Varchar, day(@data))+'/'+convert(Varchar, month(@data)) in (
'1/1',
'21/4',
'1/5',
'7/9',
'12/10',
'2/11',
'15/11',
'25/12'
))
--TODO: COLOCAR AQUI OS OUTROS FERIADOS NACIONAIS DE DIA "COMPUTÁVEL" E FAZER UMA CONSULTA A OUTRA TABELA PARA VER OS FERIADOS MUNICIPAIS
)
begin
set @result = 0
end;
else
begin
set @result = 1
end;
RETURN @result
END
GO
/*
TESTE:
SELECT dbo.fn_dia_util('2015-1-1') -- 0
SELECT dbo.fn_dia_util(GETDATE()) -- 1 SE HOJE NÃO FOR FERIADO :)
--drop function fn_dia_util
*/
</pre>
<pre class="brush: sql">-- ############################################################################################################################################
-- # NOME : fn_next_dia_util
-- # PRODUTO : blog.vitorrubio.com.br
-- # DEVELOPER : Vitor Luiz Rubio
-- # COPYRIGHT :
-- # OBJETIVO : retorna o próximo dia útil a partir de uma data
-- # VERSAO : 1.0
-- # DT. CRIACAO : 2014-10-16
-- # DT. ALTERACAO :
-- #
-- # DEPENDENCIAS :
-- #
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2014-10-16 : Criação
-- #
-- ############################################################################################################################################
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION dbo.fn_next_dia_util
(
@data datetime
)
RETURNS datetime
AS
BEGIN
declare @result datetime
set @result = dateadd(day, 1, @data)
while (dbo.fn_dia_util(@result) = 0)
begin
set @result = dateadd(day, 1, @result)
end
RETURN @result
END
GO
/*
TESTE:
SELECT dbo.fn_next_dia_util('2014-12-31') -- 2015-1-2
SELECT dbo.fn_next_dia_util('2014-04-18') -- 2014-4-22 porque segunda-feira é feriado
SELECT dbo.fn_next_dia_util(GETDATE()) -- amanhã SE NÃO FOR FERIADO :)
--drop function fn_dia_util
*/
</pre>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-75281516101836677582014-10-16T14:34:00.001-03:002014-10-16T15:40:01.966-03:00Duas maneiras de se fazer split no Delphi XE2 parecido com a função split do C#<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-u-cgVO3fYjw/VEABjZT0f6I/AAAAAAAABQo/4rq1Lf1fsmg/s1600/banana-split.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-u-cgVO3fYjw/VEABjZT0f6I/AAAAAAAABQo/4rq1Lf1fsmg/s400/banana-split.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Para se fazer uma função split no Delphi basta usar array dinâmico ou list de string.<br />
O exemplo abaixo mostra como.<br />
<br />
<br />
<pre class="brush: delphi">
function split(original: string; separador: string) : TStringArray;
var idx: integer;
tmp, item: string;
resultado: TStringArray;
begin
idx:=0;
SetLength(resultado, idx);
tmp := original;
while Pos(separador, tmp) > 0 do
begin
SetLength(resultado, length(resultado)+1);
item := Copy(tmp, 1, Pos(separador, tmp)-1);
tmp := Copy(tmp, Pos(separador, tmp) + length(separador), length(tmp) + Pos(separador, tmp) - length(separador));
resultado[idx] := item;
inc(idx);
end;
SetLength(resultado, length(resultado)+1);
resultado[idx] := tmp;
Result := resultado;
end;
function split2(original: string; separador: string) : TList < string >;
var
tmp, item: string;
begin
result := TList< string >.Create;
tmp := original;
while Pos(separador, tmp) > 0 do
begin
Result.Add( Copy(tmp, 1, Pos(separador, tmp)-1));
tmp := Copy(tmp, Pos(separador, tmp) + length(separador), length(tmp) + Pos(separador, tmp) - length(separador));
end;
Result.Add(tmp);
end;
</pre>
É isso aí, isso é usado em alguns outros posts desse blog. Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-14207312963717070102014-10-15T16:59:00.002-03:002014-10-15T17:15:44.736-03:00Reflexão no JavascriptDado um objeto javascript, é possível varrer seus métodos e propriedades e até mesmo serializá-lo. <br />
Para isso devemos fazer uma conversão forçada do objeto para um vetor, e varre-lo. Cada item desse vetor pode ser um método ou uma propriedade. <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-klIRxv9sym0/VD7Vp2og2RI/AAAAAAAABQY/S_djnhbU2M0/s1600/reflexao.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-klIRxv9sym0/VD7Vp2og2RI/AAAAAAAABQY/S_djnhbU2M0/s400/reflexao.jpg" /></a></div>
O que vai dizer se ele é um método ou uma propriedade é que seu tipo, dado pela função typeof():
<br />
<ul>
<li>quando, como string, for igual a "function" significa que ele é um método ou função. </li>
<li>caso contrário é uma propriedade.</li>
</ul>
<br />
Código da função de serialização<br />
<pre class="brush: javascript"> ///Transforma um objeto em string considerandp se é null ou undefined
function ObjToString(obj)
{
if(obj === null)
{
return "null";
}
if(typeof obj === "undefined")
{
return "undefined";
}
return obj.toString();
}
///escreve as propriedades do objeto na página
function serialize(obj)
{
//coleção de métodos
var metodos = [];
//coleção de propriedades
var propriedades = [];
//varre as propriedades
for (i in obj)
{
//verifica se não é a própria função
if (i != "serialize")
{
if (typeof(obj[i]) == "function")
{
//se for método adiciona em uma coleção
metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
}
else
{
//senão adiciona na outra
propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
}
}
}
//varre as coleções escrevendo na página
document.write("<strong>metodos</strong>
");
for (m in metodos)
{
document.write(metodos[m]+"
");
}
document.write("
<strong>propriedades</strong>
");
for (p in propriedades)
{
document.write(propriedades[p]+"
");
}
}
</pre>
No caso dessa função, ela simplesmente lista as propriedades e métodos e os concatena a seus devidos valores, pulando linha.
Isso poderia ser feito de outra forma, por exemplo, a função de serialização poderia gerar um JSON e usá-lo em uma requisição ajax,
ou interpretá-lo com eval() e gerar um clone do objeto em questão (apenas as propriedades, um DTO), ou ainda serializá-lo em XML.
Por enquanto vamos listar os métodos e propriedades na página mesmo. Depois tentamos gravar em uma string ou objeto json.<br />
Note o uso do comando for ... in. for (i in obj) <br />
Ele equivale ao foreach do c# e de outras linguagens. Ele varre todos os elementos de um array atribuindo a I o elemento do array de indice x quando for um array, ou a propriedade quando for um ojeto (como se fosse um hashtable/dictionay).
Usando esse comando, para uma varredura geral sem armazenar ou utilizar o índice, você pode fazer uma varredura geral em um array sem se preocupar com os limites inferior e superior.
<br />
A função ObjToString apenas verifica se o objeto é nulo ou undefined antes de chamar .toString() nele.
<br />
Abaixo um exemplo de serialização do objeto window:<br />
<pre class="brush: javascript"> serialize(window);
</pre>
<script>
$(document).ready(function(){
$("#saida1").hide();
$("#show1").click(function(){
$("#saida1").show();
});
$("#saida2").hide();
$("#show2").click(function(){
$("#saida2").show();
});
});
</script>
<a href="https://www.blogger.com/null" id="show1">Com a saída:</a>
<br />
<pre id="saida1"> metodos
function: postMessage: function () { [native code] }
function: close: function () { [native code] }
function: blur: function () { [native code] }
function: focus: function () { [native code] }
function: getSelection: function getSelection() { [native code] }
function: print: function print() { [native code] }
function: stop: function stop() { [native code] }
function: open: function open() { [native code] }
function: alert: function alert() { [native code] }
function: confirm: function confirm() { [native code] }
function: prompt: function prompt() { [native code] }
function: find: function find() { [native code] }
function: scrollBy: function scrollBy() { [native code] }
function: scrollTo: function scrollTo() { [native code] }
function: scroll: function scroll() { [native code] }
function: moveBy: function moveBy() { [native code] }
function: moveTo: function moveTo() { [native code] }
function: resizeBy: function resizeBy() { [native code] }
function: resizeTo: function resizeTo() { [native code] }
function: matchMedia: function matchMedia() { [native code] }
function: getComputedStyle: function getComputedStyle() { [native code] }
function: getMatchedCSSRules: function getMatchedCSSRules() { [native code] }
function: webkitConvertPointFromPageToNode: function webkitConvertPointFromPageToNode() { [native code] }
function: webkitConvertPointFromNodeToPage: function webkitConvertPointFromNodeToPage() { [native code] }
function: requestAnimationFrame: function requestAnimationFrame() { [native code] }
function: cancelAnimationFrame: function cancelAnimationFrame() { [native code] }
function: webkitRequestAnimationFrame: function webkitRequestAnimationFrame() { [native code] }
function: webkitCancelAnimationFrame: function webkitCancelAnimationFrame() { [native code] }
function: webkitCancelRequestAnimationFrame: function webkitCancelRequestAnimationFrame() { [native code] }
function: captureEvents: function captureEvents() { [native code] }
function: releaseEvents: function releaseEvents() { [native code] }
function: btoa: function btoa() { [native code] }
function: atob: function atob() { [native code] }
function: setTimeout: function setTimeout() { [native code] }
function: clearTimeout: function clearTimeout() { [native code] }
function: setInterval: function setInterval() { [native code] }
function: clearInterval: function clearInterval() { [native code] }
function: webkitRequestFileSystem: function webkitRequestFileSystem() { [native code] }
function: webkitResolveLocalFileSystemURL: function webkitResolveLocalFileSystemURL() { [native code] }
function: openDatabase: function openDatabase() { [native code] }
function: addEventListener: function addEventListener() { [native code] }
function: removeEventListener: function removeEventListener() { [native code] }
function: dispatchEvent: function dispatchEvent() { [native code] }
propriedades
object: top
object: window
object: location
object: external
object: chrome
object: document
object: speechSynthesis
object: localStorage
object: sessionStorage
object: applicationCache
object: webkitStorageInfo
object: indexedDB
object: webkitIndexedDB
object: crypto
object: CSS
object: performance
object: console
number: devicePixelRatio
object: styleMedia
object: parent
object: opener
object: frames
object: self
string: defaultstatus
string: defaultStatus
string: status
string: name
number: length
boolean: closed
number: pageYOffset
number: pageXOffset
number: scrollY
number: scrollX
number: screenTop
number: screenLeft
number: screenY
number: screenX
number: innerWidth
number: innerHeight
number: outerWidth
number: outerHeight
boolean: offscreenBuffering
object: frameElement
object: clientInformation
object: navigator
object: toolbar
object: statusbar
object: scrollbars
object: personalbar
object: menubar
object: locationbar
object: history
object: screen
object: onautocompleteerror
object: onautocomplete
object: ondeviceorientation
object: ondevicemotion
object: onunload
object: onstorage
object: onpopstate
object: onpageshow
object: onpagehide
object: ononline
object: onoffline
object: onmessage
object: onlanguagechange
object: onhashchange
object: onbeforeunload
object: onwaiting
object: onvolumechange
object: ontoggle
object: ontimeupdate
object: onsuspend
object: onsubmit
object: onstalled
object: onshow
object: onselect
object: onseeking
object: onseeked
object: onscroll
object: onresize
object: onreset
object: onratechange
object: onprogress
object: onplaying
object: onplay
object: onpause
object: onmousewheel
object: onmouseup
object: onmouseover
object: onmouseout
object: onmousemove
object: onmouseleave
object: onmouseenter
object: onmousedown
object: onloadstart
object: onloadedmetadata
object: onloadeddata
object: onload
object: onkeyup
object: onkeypress
object: onkeydown
object: oninvalid
object: oninput
object: onfocus
object: onerror
object: onended
object: onemptied
object: ondurationchange
object: ondrop
object: ondragstart
object: ondragover
object: ondragleave
object: ondragenter
object: ondragend
object: ondrag
object: ondblclick
object: oncuechange
object: oncontextmenu
object: onclose
object: onclick
object: onchange
object: oncanplaythrough
object: oncanplay
object: oncancel
object: onblur
object: onabort
object: onwheel
object: onwebkittransitionend
object: onwebkitanimationstart
object: onwebkitanimationiteration
object: onwebkitanimationend
object: ontransitionend
object: onsearch
number: TEMPORARY
number: PERSISTENT
</pre>
Agora imagine um objeto json, por exemplo pessoa:
<br />
<pre class="brush: javascript"> var pessoa = {
nome:"Vitor",
sobrenome:"Rubio",
email:"vitorrubio@gmail.com",
idade:30,
dataCadastro:"14/10/2014",
dependente:null,
hobby:undefined};
</pre>
<a href="https://www.blogger.com/null" id="show2">Com a saída:</a>
<br />
<pre id="saida2"> metodos
propriedades
string: nome: Vitor
string: sobrenome: Rubio
string: email: vitorrubio@gmail.com
number: idade: 30
string: dataCadastro: 14/10/2014
object: dependente: null
undefined: hobby: undefined
</pre>
Repare também que foi necessário colocar uma excessão quanto ao método "serialize" para ele não serializar a si mesmo.
Se um método for nativo do browser ele é serializado como [native code], mas se for um método seu então todo o source do método é serializado.
Veja o poder disso: nas linguagens compiladas como C ou Delphi, ou nas linguagens com compilação Just In Time como C# e Java, os objetos podem ter suas propriedades e valores varridos, serializando-os para xml, json e outros formatos. Mas apenas seus campos e propriedades. NUNCA SEUS MÉTODOS.
Então nas aplicações, não importa se você usa um banco de dados relacional ou orientado a objeto, você nunca poderia armazenar o código executável (métodos) no banco de dados. Apenas os dados poderiam ser armazenados. Isso significaria ter que tratar os dados com functions e stored procedures no banco de dados ou reconstituir o objeto e tratar na aplicação.
Com javascript é diferente. Você pode salvar o SOURCE de métodos e argumentos em um banco de dados, trazêlos de volta a vida com eval(), JSON.parse ou jQuery.parseJSON e executar as mesmas funções que eles já possuiam.
Não é possível fazer isso com JSON.parse(), apenas com eval, pois entende-se que o JSON é apenas para transferência de DADOS. Mesmo assim você pode embutir o eval como mostrado <a href="http://ovaraksin.blogspot.com.br/2013/10/pass-javascript-function-via-json.html">nesse link</a>
<br />
O método abaixo faz o mesmo que o serialize, mas joga o resultado em uma string.
<br />
<pre class="brush: javascript"> ///o mesmo que serialize só que retornando uma string
function SerializeObjToString(obj)
{
var metodos = [];
var propriedades = [];
var resultado = "";
for (i in obj)
{
//tirada a restrição do "serialize". Deixa trazer tudo.
if (typeof(obj[i]) == "function")
{
metodos.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
}
else
{
propriedades.push(typeof(obj[i]) + ": " + i + ": " + ObjToString(obj[i]) );
}
}
//a string já é formatada
resultado+="<strong>metodos</strong>
";
for (m in metodos)
{
resultado+=metodos[m]+"
";
}
resultado+="
<strong>propriedades</strong>
";
for (p in propriedades)
{
resultado+=propriedades[p]+"
";
}
return resultado;
}
</pre>
O método abaixo transforma o objeto javascript em uma string JSON.
<br />
<pre class="brush: javascript"> ///gera uma string json para ser interpretada com eval ou json.parse
///não é segura quanto à recursividade, referência cíclica
function SerializeObjToJSON(obj)
{
var metodos = [];
var propriedades = [];
var resultado = "";
for (i in obj)
{
//tirada a restrição do "serialize". Deixa trazer tudo.
//verifica primeiro se o objeto é undefined, para retornar undefined
if(typeof (obj[i]) === "undefined")
{
metodos.push("\""+i+"\"" + ":" + "\"undefined\"" );
}
//se for uma function retorna o corpo da mesma com ObjToString sem aspas
else if (typeof(obj[i]) == "function")
{
metodos.push("\""+i+"\"" + ":" + ObjToString(obj[i]) );
}
//se for um número usa ObjToString para retornar sem aspas
else if (typeof(obj[i]) == "number")
{
metodos.push("\""+i+"\"" + ":" + ObjToString(obj[i]) );
}
//se for objeto verifica se é nulo ou não
else if (typeof(obj[i]) == "object")
{
//se for nulo simplesmente concatena null
if(obj[i] === null)
{
metodos.push("\""+i+"\"" + ":" + "\"null\"" );
}
//senão chama a propria função e serializa recursivamente
else
{
metodos.push("\""+i+"\"" + ":" + SerializeObjToJSON(obj[i]) );
}
}
else
{
//senão assume que é string e poe entre aspas. Se tiver errado é fácil alterar.
propriedades.push("\""+i+"\"" + ":\"" + ObjToString(obj[i])+"\"" );
}
}
//começa e termina entre chaves
resultado+="{";
for (var m = 0; m<metodos .length="" adiciona="" for="" if="" igual="" m="" metodos.length-1="" metodos="" propriedades.length="" propriedades="" resultado="" s="" se="" tamb="" tiver="" virgula=""> 0)
{
resultado+=",";
}
}
else
{
resultado+=",";
}
resultado+="\r\n";
}
for (var p = 0; p < propriedades.length; p++)
{
resultado+=propriedades[p];
if(p < propriedades.length-1)
{
resultado+=",";
}
resultado+="\r\n";
}
resultado+="}";
return resultado;
}
</metodos></pre>
Que pode ser transformada de volta em objeto da seguinte maneira.
<br />
<pre class="brush: javascript"> function evalJson()
{ try
{
//poe a string entre parenteses antes do eval
var txt = SerializeObjToJSON(pessoa);
alert(txt);
//var obj = eval("(" + txt + ")"); //para usar eval
var obj = JSON.parse(txt); //para usar JSON.parse nativo
//var obj = JSON && JSON.parse(txt) || $.parseJSON(txt); //para decidir de acordo com o browser se vai usar JSON nativo ou a versão do jQuery
alert(obj.email);
}
catch(e)
{
alert(e.message);
}
}
</pre>
Bom, por enquanto é isso. Acredito que esse é o meu maior post sobre javascript. Pretendo postar amanhã uma galeria com jQuery e dar uma organizada nesse blog. <br />
<a href="http://www.vitorrubio.com.br/downloads/serializeJs.7z">Baixar o Exemplo</a><br />
Have fun :)
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-65811180975367400552014-09-08T16:08:00.000-03:002014-09-08T16:37:15.111-03:00Consultando apenas os registros "sujos" em uma tabela com Microsoft SQL ServerLidando com bancos de dados podemos controlar as transações e a maneira como podemos acessar os dados em transações concorrentes. <br />
<br />
Os níveis de isolamento de transação e os comandos para tais serão discutidos em um próximo post, porém, resumidamente, temos (Serializável, snapshot, repeatable read, read commited, read uncommited).<br />
<br />
Dirty read (read uncommited ou nolock) nos permitem visualizar os dados de uma tabela mesmo sendo sujos (alterados em outras transações). Isso garante, com certo nível de inconsistência se as transações forem desprezadas e o rollback usado, uma leitura o mais rápido possível dos dados no seu estado atual quase que em tempo real.<br />
<div>
<br /></div>
No entanto, como separar os dados "sujos" daqueles que já estavam gravados e commitados?<br />
Imagine que você tem um ambiente onde um sistema legado permite que a aplicação seja fechada, após uma exception ou queda de rede, sem dar commit ou rollback nas transações correntes. Você rapidamente ficaria com várias transações em aberto, utilizando recursos do servidor e dando table locks ou situações de deadlock. Como saber quais são os dados não commitados?<br />
<br />
Em um cenário real, como saber quais dados podem não ser consistentes porque estão sendo alterados neste momento, em uma transação ainda não finalizada?<br />
<br />
O comando / table hint nolock depois do nome da tabela nos permite fazer uma dirty read e visualizar tanto os dados antigos (commitados) como os não commitados. Já o comando readpast faz uma leitura sem lock (somente leitura) da tabela trazendo apenas os dados commitados. Então, para sabermos os dados não comitados basta usar not exist ou except.<br />
<br />
Dado o seguinte cenário:<br />
<br />
<pre class="brush:sql">create table teste
(
valor varchar(50)
)
insert into teste values ('comitado')
select * from teste
begin transaction --rollback
insert into teste values ('nao comitado')
</pre>
<br />
<br />
<strong>Not Exist</strong>
<br />
<br />
<pre class="brush:sql">select * from teste(nolock) where valor not in (select valor from teste (READPAST ))
</pre>
<br />
<br />
<br />
<strong>Except</strong>
<br />
<br />
O Except funciona como not in ou not exists, mas sem especificar uma coluna ou pk: você simplesmente especifica a query com os resultados que você NÃO quer que apareça.
<br />
<pre class="brush:sql">SELECT * FROM teste WITH (nolock)
EXCEPT
SELECT * FROM teste WITH (READPAST)
</pre>
<br />
Com esses comandos você pode verificar quais são os comandos "sujos" de transações ainda não "commitadas" do seu banco de dados. O except ainda te ajudará com relatórios mais elaborados onde você deverá especificar com um filtro complexo um conjunto de resultados que você não quer trazer na sua consulta mas não tem uma chave primária ou não tem exatamente um campo único para comparar.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Yn74IOljiPk/VA4E1bPWeUI/AAAAAAAABP8/jtt9A3FIE5s/s1600/origin_11122773785.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Yn74IOljiPk/VA4E1bPWeUI/AAAAAAAABP8/jtt9A3FIE5s/s1600/origin_11122773785.jpg" height="212" width="320" /></a></div>
<br />
<br />
<br />
<div class="LeiaMais">
<a href="http://technet.microsoft.com/pt-br/library/ms189122(v=sql.105).aspx" target="_blank">Níveis de Isolamento</a><br />
<a href="http://pt.wikipedia.org/wiki/Transa%C3%A7%C3%A3o_em_base_de_dados" target="_blank">Transações em Bancos de Dados</a><br/>
<a href="http://www.techrepublic.com/article/using-nolock-and-readpast-table-hints-in-sql-server/" target="_blank">nolock vs readpast</a>
</div>
photo credit: <a href="https://www.flickr.com/photos/92334668@N07/11122773785/">tec_estromberg</a> via <a href="http://photopin.com/">photopin</a> <a href="http://creativecommons.org/licenses/by/2.0/">cc</a>Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-13951598355361648722014-04-13T00:04:00.000-03:002014-04-13T00:09:47.397-03:00Como ordenar o conteúdo de um Memo com regras personalizadasRecentemente um colega delpheiro me perguntou como ordenar um memo não pelo seu conteúdo, mas por alguma regra especial.<br />
<br />
No caso dele, ele tinha no memo várias strings separadas por ":" com números do outro lado. Algo assim:<br />
<br />
A:3<br />
B:5<br />
C:1<br />
<br />
Devendo ficar:<br />
<br />
C:1<br />
A:3<br />
B:5<br />
<br />
Para isso podemos usar a função CustomSort do memo, passando como argumento uma função. Essa é uma função especial que aceita uma lista como parâmetro, dois índices da lista e retorna um integer. Assim ela pode comparar dois itens da lista e retornar 1 se o primeiro for maior, 0 se os itens forem iguais ou -1 se o segundo for maior.<br />
Essa função é que fará todo o trabalho de comparação, portanto você decide como os itens serão comparados. A função CustomSort saberá que deve chamar a sua função para decidir, na varredura, qual item é maior porque você passará o nome da sua função, como se fosse um delegate ou ponteiro para função, como argumento para a função customsort.<br />
<br />
Os memos podem ser usados como dictionaries, ou como arquivos ini, eles podem ter pares de namve/value, e para isso você define a propriedade NameValueSeparator. Definindo esta propriedade como ":" os valores são automaticamente separados em duas partes.<br />
<br />
O código ficou como abaixo:<br />
<br />
<pre class= "brush:delphi">
//crio uma function inline que compara só dois valores e diz qual é o maior
//ela é usada automaticamente para comparar os valores 2 a 2 dentro da função
//customsort do stringlist e ordenar a parada toda
function compara(List: TStringList; Index1, Index2: Integer): Integer;
var val1: integer;
val2: integer;
begin
//defino que o separador e chave / valor NameValueSeparator é ':', a string separadora.
List.NameValueSeparator := ':';
val1 := StrToInt( List.ValueFromIndex[Index1]);
val2 := StrToInt( List.ValueFromIndex[Index2]);
//quando você coloca o delimitador de um tstringlist você pode separar ele em key e value
//essa função pode ser anonima
//se o valor do indice 1 for maior que o 2 retorna 1
if(val1 > val2) then
Result := 1
//se for menor retorna -1
else if(val2 > val1) then
Result := -1
else
//se for igual retorna zero
Result := 0;
//esses resultados -1, 0 e 1 são o padrão de todos os comparers
end;
procedure TForm1.Button1Click(Sender: TObject);
//crio um stringlist temporário para guardar o conteudo ordenado
var str: TStringList;
begin
str := TStringList.Create;
//mando o conteudo do memo para o stringlist
str.AddStrings(Memo1.Lines);
//mando ordenar passando como parâmetro a função ordenadora (existem
//funções que aceitam outras funções como parâmetro, não o retorno dela, mas seu escopo, ela será executada internamente)
str.CustomSort( compara );
//limpa o memo1
Memo1.Clear;
//adiciona o valor ja ordenado
Memo1.Lines.AddStrings(str);
//destroi o stringlist
str.Free;
end;
</pre>
<br />
Have fun :)<br />
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com1tag:blogger.com,1999:blog-120161195353369613.post-22807665477096253472014-04-02T18:25:00.000-03:002014-04-02T18:25:18.080-03:00Validação e conversão de datas<p>Dentre os problemas mais recorrentes em sistemas podemos citar os relacionados à cultura: charset, datas e formatação de números.</p>
<p>Datas são especialmente problemáticas porque podem ser ambíguas dependendo da cultura, por exemplo 02/01/1990 pode ser dois de janeiro no Brasil ou primeiro de fevereiro nos EUA.</p>
<p>Ainda mais agravante é o fato de nem sempre podermos validar as datas nos imputs, pois as mesmas podem vir de arquivos de integração, outros sistemas, CSV, TXT, Excel ou webservices.</p>
<p>Pensando nisso eu fiz uma pequea demonstração do uso dos comandos cast e convert para converter varchar para datas e datas para varchar, e mostrando onde estão os erros mais comuns.</p>
<br />
<br />
<pre class="brush: sql">/*******************************************************************************************************
******************************** DEMONSTRAÇÃO DE CONVERSÃO DE DATAS ************************************
********************************************************************************************************/
--imagine que tipo de coisa pode vir em um campo de "data" que não é datetime, ou um arquivo xml, txt, csv mal convertido
--imagine também o problema de gravar a data em uma linguagem, formatar para exibição em outra, e os problemas que sempre acontecem ao se converter string de um campo de texto para datetime
/*************************************** teste do convert *********************************/
--qual é a data zero
select convert (datetime, 0, 103)
--R: é a data 1900-01-01 00:00:00.000
--e se a data for null?
select convert (datetime, null, 103)
--R: null
--E se a data for uma string vazia?
select convert (datetime, '', 103)
--R: é a mesma coisa que a data zero 1900-01-01 00:00:00.000 (aqui eu acho que deveria dar um erro)
--mesma coisa só que usando o padrão americano
select convert (datetime, 0, 101)
--1900-01-01 00:00:00.000
select convert (datetime, null, 101)
--null
select convert (datetime, '', 101)
--1900-01-01 00:00:00.000
/*************************************** teste do cast *********************************/
select cast (null as datetime)
--como esperado, null
select cast (0 as datetime)
--como esperado, a data zero 1900-01-01 00:00:00.000
select cast ('' as datetime)
--1900-01-01 00:00:00.000
--agora, se em um arquivo de texto ou xml você tem uma data 0 (zero) ou '' (string vazia), isso é essencialmente um erro. Não quer dizer que a data real seja em primeiro de janeiro de 1900, mas sim que o campo não foi preenchido, logo, certos literais deveriam ser convertidos para null
select CAST(nullif(/*campo_que_pode_ser_string_vazia*/'','') as datetime)
select CAST(nullif(/*campo_que_pode_ser_zero*/0,0) as datetime)
--para todos os casos
select CAST(
coalesce(
nullif(/*campo_que_pode_ser_string_vazia*/'',''), --se for null tenta o proximo ...
nullif(/*campo_que_pode_ser_zero*/0,0), --- que se for null de novo vai null mesmo
null) as datetime)
/***********************************************************************************************************************
******************************************** exemplos de problemas de conversão de datas *******************************
***********************************************************************************************************************/
--fique atento quando as datas podem vir de outros bancos de dados, de sistemas que formatam de uma forma não canônica e quando você está usando o cast em vez do convert com formato específico
--troque 2014 pelo ano corrente e não faça esse teste em 1º de janeiro
--o que é maior, a data de hoje ou 2014-12-01 ?
select ( cast ('2014-12-1' as datetime)), getdate(), case when cast ('2014-12-1' as datetime) > getdate() then 'Maior' else 'Menor' end
--como estamos em março, primeiro de dezembro é maior
--o que é maior, a data de hoje ou 2014.12.1 ?
select (cast ('2014.12.1' as datetime)), getdate(), case when cast ('2014.12.1' as datetime) > getdate() then 'Maior' else 'Menor' end
--padrão Brasileiro
--o que é maior, a data de hoje ou 2014-12-01 ?
select ( convert (datetime,'2014-12-1', 103)), getdate(), case when convert (datetime,'2014-12-1', 103) > getdate() then 'Maior' else 'Menor' end
--como estamos em março, primeiro de dezembro é maior
--o que é maior, a data de hoje ou 2014.12.1 ?
select (convert (datetime,'2014.12.1', 103)), getdate(), case when convert (datetime,'2014.12.1', 103) > getdate() then 'Maior' else 'Menor' end
--padrão americano
--o que é maior, a data de hoje ou 2014-12-01 ?
select ( convert (datetime,'2014-12-1', 101)), getdate(), case when convert (datetime,'2014-12-1', 101) > getdate() then 'Maior' else 'Menor' end
--como estamos em março, primeiro de dezembro é maior
--o que é maior, a data de hoje ou 2014.12.1 ?
select (convert (datetime,'2014.12.1', 101)), getdate(), case when convert (datetime,'2014.12.1', 101) > getdate() then 'Maior' else 'Menor' end
--isso mostra que o formato AAAA-MM-DD ou AAAA.MM.DD, nessa ordem, sempre é interpretado corretamente pelo SQL, independente da linguagem. Agora coisas estranhas podem ocorrer se você obtiver uma data da qual não sabe o formato e tentar converter para datetime forçando uma formatação brasileira ou americana
--lembre-se também que o CAST depende da data do sistema.
--Faça de tudo para, tanto para datas como para formatos numéricos, nunca depender das informações de localização e linguagem do servidor de SQL mas depender somente do servidor WEB e do .net framework, ou, na melhor das hipóteses, o que o usuário informar em suas preferências.
--padrão Brasileiro
select ( convert (datetime,'01/12/2014', 103)), getdate(), case when convert (datetime,'01/12/2014', 103) > getdate() then 'Maior' else 'Menor' end
--beleza
select (convert (datetime,'01.12.2014', 103)), getdate(), case when convert (datetime,'01.12.2014', 103) > getdate() then 'Maior' else 'Menor' end
--beleza
--padrão americano
select ( convert (datetime,'01/12/2014', 101)), getdate(), case when convert (datetime,'01/12/2014', 101) > getdate() then 'Maior' else 'Menor' end
--epa!
select (convert (datetime,'01.12.2014', 101)), getdate(), case when convert (datetime,'01.12.2014', 101) > getdate() then 'Maior' else 'Menor' end
--epa!
</pre>
<p>
Porém não é apenas nas rotinas de banco de dados que devemos nos preocupar com as datas. Em sistemas data centric ou orientados a dados, ou com muitas stored procedures, as dicas acima são uma mão na roda, mas em sistemas orientados a objetos onde o problema das datas é resolvido no domínio da aplicação, via código, é bom conhecer as ferramentas disponibilizadas pelo seu ambiente.
</p>
<p>
No caso do C# temos Culture, e as ferramentas para identificar a culture corrente, sugerir uma padrão ou modificar a Culture.
</p>
<p>
Um outro problema relacionado são as datas no nosso domínio que podem ser nulas, mas que devemos em algum momento converter para string dependendo da aplicação para sua exibição.
Nesses casos provavelmente você tem no seu banco de dados um campo null, e na aplicação um DateTime? nulável.
Soma-se a isso o fato de a data mínima do banco de dados ser muito maior do que a data mínima na aplicação. Isso gera muito código repetitivo onde se verifica se uma data é nula, depois verifica-se se ela é a data mínima para só então fazer a conversão. <br/>
Isso pode ser feito via extension method de DateTime ou um método de uma classe estática, mais ou menos como abaixo, e poupar muito código repetitivo:
<p>
<pre class="brush:c#">
public static string DateToString(DateTime? data)
{
//se for nula retorna string vazia
if (data == null)
{
return "";
}
//não sei se é possível não ser nula e não ter um valor, acho que essas três linhas são inúteis, mas são uma alternativa às três linhas de cima
if (!data.HasValue)
{
return "";
}
//se a data for menor ou igual a data mínima do banco de dados é porque era para ser originalmente nula e foi erroneamente gravada ou exportada de forma incorreta (para um arquivo texto com a data mínima em vez de branco, por exemplo).
if (data.Value <= new DateTime(1900, 1, 1))
{
return "";
}
//...
//código para obter a culture corrente ou escolhida pelo usuário
//...
//devolvendo a data como string
//em um formato padrão
//return data.Value.ToString("dd/MM/yyyy");
//ou dependente da culture
return data.Value.ToString(CultureEncontrada);
}
</pre>
<p>
Uma dica simples, em breve mais dicas sobre cultura, encoding e afins.
</p>
Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-6182523462093675572014-03-19T17:59:00.000-03:002014-03-19T18:07:41.967-03:00Criando um identificador único no excelPara criar um identificador único no exel, tanto para identificar uma linha sem repetições como para fazer scripts para exportar os dados do excel para um banco de dados é necessário abrir o editor de código VBA do excel, na aba Developer.<br />
Caso a guia não esteja aparecendo para você clique em file -> options -> customize ribbon e marque a opção developer à direita.
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-Im28ZQvPVLI/UyoDJHSh5wI/AAAAAAAAAoI/aYm-YFreZgA/s1600/habilitar-barra.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Im28ZQvPVLI/UyoDJHSh5wI/AAAAAAAAAoI/aYm-YFreZgA/s1600/habilitar-barra.png" /></a></div>
<br/>
Na aba developer abra o editor do visual basic, crie um novo módulo e adicione o código.
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-ePNeytIYr98/UyoFGmNesII/AAAAAAAAAoU/PtPKoM7W4M0/s1600/developer.xlsm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-ePNeytIYr98/UyoFGmNesII/AAAAAAAAAoU/PtPKoM7W4M0/s1600/developer.xlsm.png" /></a></div>
<pre class="brush:vb">
Public Function NewId() As String
NewId = Mid$(CreateObject("Scriptlet.TypeLib").Guid, 2, 36)
End Function
Public Function NewGuid() As String
NewGuid = CreateObject("Scriptlet.TypeLib").Guid
End Function
</pre>
<br />
A função NewId é igual a newid() do sql server e cria uma Guid sem as chaves no início e fim. A NewGuid está aí só para demonstração e apresenta guids com as chaves.
<br />
Ambas usam o objeto COM Scriptlet.TypeLib e chamam o método Guid.
<br />
Eu uso isso quando eu tenho que importar dados de uma planilha excel para um banco de dados qualquer sem usar DTS ou algum programa para isso: faço uma formuleta excel que concatena strings em uma linha fazendo um script de inserts, concateno os valores das células que quero e uso uma guid gerada por essa função como chave primária.
<br/>
Você pode fazer download dessa planilha aqui <a href="http://www.4shared.com/file/G3KlLekece/guid.html" target=_blank>guid.xlsm</a>
<br/>
Have FunVitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-35051879845348539252014-03-19T16:52:00.001-03:002014-03-19T17:28:13.845-03:00Essa é pra quem curte DunaPra quem conhece, vai entender de primeira.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.livrariacultura.com.br/scripts/cultura/externo/index.asp?id_link=8055&tipo=2&isbn=8576571013" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img alt="" border="0" src="http://1.bp.blogspot.com/-s7GCHqNwsOM/UynzYAZIpEI/AAAAAAAAAn4/IvjXvvz9d94/s1600/shai_hulud_donkey.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Na boa, sem fazer spoil, esse livro é um dos melhores que eu já li, tem espaço especial dedicado a ele na minha estante. </div>
<div class="separator" style="clear: both; text-align: left;">
Ele simplesmente mistura à ficção científica elementos de religião, filosofia, política e ecologia. Muito avançado para o seu tempo, e praticamente profético se levarmos em conta o caminho que estamos trilhando rumo ao esgotamento da água potável do planeta. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Leitura recomendada. </div>
<br />Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com0tag:blogger.com,1999:blog-120161195353369613.post-45427308089950727882013-12-18T14:54:00.002-02:002013-12-18T15:13:52.107-02:00Evitar duplo submit com jQueryNo trabalho hoje me deparei com a necessidade de impedir que se façam múltiplos submits em uma página Web.<br />
<br />
Na empresa onde trabalho não usamos asp.net MVC ou Web Forms, mas sim um framework próprio da empresa, feito sobre asp.net, que lembra muito o asp clássico.<br />
<br />
Independente do ambiente ou framework, de ser em php, .net etc, se não houver um recurso nativo para evitar isso então você deve se preocupar: lentidão para enviar a página e o usuário com "dedinho nervoso" clicando em enviar mil vezes por segundo, levando a múltiplos posts (submits) e a inserir mútiplos dados idênticos no seu banco de dados.<br />
<br />
Além do trabalho server-side, de validação, prevenção de duplicidades na camada de persistência, redirect para uma página de sucesso etc, deve haver alguma coisa client-side para prevenir o submit duplo.<br />
<br />
Com javascript é possível desabilitar o botão no momento do click, e evitar que ele seja pressionado novamente.<br />
Se for um Button do tipo AspButton (System.Web.UI.WebControls.Button), da paleta Web do Visual Studio, num ambiente Web Forms, talvez você deseje adicionar o script como um atributo do botão, no evento load da página.<br />
<br />
Com jQuery fica muito fácil, e funciona de uma vez para todas as forms e botões de uma página.<br />
<br />
De todos os scripts que eu fucei o desse site <a href="http://thepugautomatic.com/2008/07/jquery-double-submission/">http://thepugautomatic.com/2008/07/jquery-double-submission/</a> me pareceu o melhor. Ele praticamente cria uma função nova no jQuery, que você pode reusar em todas as páginas com uma linha de código.<br />
<br />
<br />
<br />
<pre class="brush: javascript">//isso você coloca em um arquivo js externo, a ser chamado depois do jquery, ou na tag script de uma página
jQuery.fn.preventDoubleSubmit = function() {
jQuery(this).submit(function() {
if (this.beenSubmitted)
return false;
else
this.beenSubmitted = true;
});
};
</pre>
<br />
<pre class="brush: javascript">//isso você coloca dentro do $(document).ready
$(document).ready(function()
{
jQuery('form').preventDoubleSubmit();
}
</pre>
E está pronto: só de incluir essa pequena linha já resolve todos os problemas de dedo nervoso nas suas páginas.
<br />
<br />
Tentei também outros scripts, e o script abaixo também funcionou muito bem, embora peque quanto à elegância e ao reaproveitamento de código: <br />
<br />
<pre class="brush: javascript">//esse embora diferente, faz a mesma coisa que o script acima: atua na interceptação do submit da form, mas desabilita os botões logo após o submit
$('form').submit(function() {
if(typeof jQuery.data(this, "disabledOnSubmit") == 'undefined') {
jQuery.data(this, "disabledOnSubmit", { submited: true });
$('input[type=submit], input[type=button]', this).each(function() {
$(this).attr("disabled", "disabled");
});
//$('input[type=submit], input[type=button]', this).attr("disabled", "disabled");
return true;
}
else
{
return false;
}
});
</pre>
<pre class="brush: javascript"></pre>
Esse terceiro script não funcionou muito bem, não sei explicar porque, mas ele deveria atuar no evento click, sumindo com o botão (ou desabilidando-o) logo o clique aconteça.<br />
<pre class="brush: javascript"></pre>
<pre class="brush: javascript">//esse atua de forma diferente: tenta interceptar o click
$('input[type=submit], input[type=button]').live('click', function(){
if(!$(this).prop("disabled"))
{
$('input[type=submit], input[type=button]', this).each(function() {
$(this).attr("disabled", "disabled");
});
//$('input[type=submit], input[type=button]', this).attr("disabled", "disabled");
return true;
}
else
{
return false;
}
});
</pre>
<br />
Uma coisa que o primeiro script não faz é desabilitar ou esconder os botões, mas basta adicionar a linha $('input[type=submit], input[type=button]', this).attr("disabled", "disabled") para fazer isso. Detalhe que em ambos os scripts eu deixei essa linha comentada. É que as linhas acima já fazem isso varrendo todos os resultados do seletor com um .each(), onde eu posso aproveitar para colocar mais comportamento nesse código.<br />
<br />
No seletor, estou passando thi como contexto, como visto na linha acima. Não sei porque, se omitir isso, não conseguimos fazer sequer uma submissão.<br />
<br />
Fique atento, no jQuery, à diferença entre .prop e .attr, explicarei isso num próximo post.Vitor Rubiohttp://www.blogger.com/profile/09819146101627563485noreply@blogger.com3