Delphi Prism no Visual Studio .NET
Agora é oficial: ontem foi anunciada a próxima versão do Delphi for .NET, que se chamará Delphi Prism e será lançada até dezembro no CodeGear RAD Studio 2009. Ao invés da IDE do RAD Studio, funcionará como um plug-in de linguagem do Microsoft Visual Studio. O Delphi Prism é baseado na tecnologia Oxygene licenciada da RemObjects, como já havia sido comentado por de Erick Sasse no início do mês.
Resumindo as informações que já se tem do Delphi Prism:
- Adeus VCL.NET - já vai tarde.
- A linguagem traz recursos avançados como nullable types e “future” types, generics, sequences e query expressions (LINQ)
- Funcionará com as tecnologias WPF, Silverlight, ASP.NET and LINQ
- ADO.NET e ASP.NET providers baseados em dbExpress
- DataSnap cliente, para conectar servidores DataSnap feitos em Win32
- BlackFish SQL database
- Precisará do .NET Framework 3.5 para rodar o VisualStudio
- Produz executáveis compatíveis com qualquer versão do .NET Framework a partir da 1.1
- Produz executáveis compatíveis com o framework .NET Mono, para Linux e Mac
- Onde já tem Visual Studio instalado será apenas adicionado o plug-in de linguagem ao sistema
- Onde não tem Visual Studio este será instalado apenas com a linguagem Delphi Prism (sem C# e VB)
- Não será preciso adquirir uma nova licença do Visual Studio
- Ainda não é possível desenvolver aplicativos .NET Compact Framework. A culpa não é da CodeGear, mas da Microsoft, que fez o CF fechado para as linguagens dela e não ao CLR
- A CodeGear/Embarcadero e a RemObjects são parceiros comerciais. Uma não comprou, nem vai comprar a outra
- O linguagem em si continuará a cargo da equipe de compiladores da RemObjects
TField.Name do seu jeito
Cada equipe de desenvolvimento tem sua convenção de nomenclatura de campos no banco de dados. Há quem prefira só letras maiúsculas ou só letras minúsculas. Há quem use CamelCase, que é o padrão Pascal/Delphi. Há quem use sublinhado (’_') para separar palavras e há quem não use. Sem argumentos aqui sobre qual é melhor e qual é pior.
O que é chato é criar campos persistentes para um dataset na IDE do Delphi e ver o nome dos componentes TField ficar com o nome formatado como na base de dados.
Dependendo da sua convenção, um dataset chamado cdsCliente, por exemplo, pode criar objetos TField com nomes estranhos como cdsClienteNOME, cdsClientenome_cliente ou cdsClienteENDERECO_BAIRRO. Todo esses casos fogem ao estilo padrão de nomenclatura de identificadores no Delphi (Object Pascal Style Guide, de Charles Calvert).
Decidido a encontrar de uma vez por todas uma solução para esse problema, fui em busca da fonte da VCL. A princípio, a unit DB era o lugar que me pareceu mais óbvio para buscar o momento em que um TField é criado. De fato, é mesmo criado ali por um método de TFieldDef, mas… coisa estranha, em nenhum momento a propriedade Name é atribuída.
Descobri afinal que a definição do nome de um TField é feita somente pela IDE, através de “component editors”. Graças a São Borland! Assim não teria que criar um descendente de TDataSet, o que seria um preço alto demais a pagar. Tudo que tive que fazer é criar um desdencente de TDSDesigner, sobrescrever o método virtual DoCreateField reformatando a propriedade Name como eu queria e registrar o novo “component editor”.
O código final tem apenas 74 linhas e uma vez instalado como um package na IDE é totalmente transparente a sua utilização. Apenas adicione os campos pelo “Fields Editor” e a formatação dos nomes será automática.
Nos exemplos anteriores, com o pacote instalado os componentes TField seriam criados como cdsClienteNome, cdsClienteNomeCliente ou cdsClienteEnderecoBairro, livres de sublinhados e maiúsculas.
O código fonte está disponível para download.
Só testei em Delphi 2007. Quem quiser testar em outras versões e me dar um feedback será bem vindo. De antemão eu sei que não vai compilar direto em versões anteriores ao Delphi 6, por causa das mudanças na unit DesignIntf, mas isso pode ser ajustado sem muita dificuldade.
Previna AV com Assert
Uma das razões mais comuns para acontecer Access Violations (AV) nos programas é quanto se tenta acessar um método ou uma propriedade de um objeto que ainda não foi alocado ou que já foi desalocado da memória.
Por exemplo:
procedure AV; var List: TStringList; begin // AV porque List é um objeto não alocado List.Add('teste'); // ok, porque List foi previamente alocado List := TStringList.Create; List.Add('novamente'); // AV, porque o objeto foi desalocado e o valor // da variável List é um ponteiro inválido List.Free; List.Add('outra vez'); // AV da mesma forma que antes, apenas a // variável aponta para nil ($0000:0000) List := nil; List.Add('e finalmente'); end;
Essas são receitas certas pra cometer violações de acesso de leitura de memória. Normalmente, em blocos de código pequenos esse tipo de coisa não ocorre, porque temos mais visibilidade e controle sobre o tempo de vida das variáveis. O problema fica maior quando o objeto é um parâmetro recebido de outra parte qualquer do código. Quem garante que o valor passado como parâmetro é válido?
Só pra ficar claro:
procedure ShowText(List: TStringList); begin ShowMessage(List.Text); // AV? List é válido? end; procedure TestAV; var Strings: TStringList; begin ShowText(Strings); end;
Aqui TestAV chama ShowText passando como parâmetro um valor de objeto inválido, porque nunca foi alocado. Seja o valor igual a nil ou uma valor aleatório qualquer (dependendo do contexto, a variável pode conter “lixo” de memória), quando ShowText usar a propriedade Text do objeto vai produzir um AV.
O que eu uso para prevenir esses casos é um Assert básico.
O código acima com Assert ficaria assim:
procedure ShowText(List: TStringList); begin // Exceção (EAssert) caso List seja inválido Assert(List <> nil); // A partir daqui é seguro usar List ShowMessage(List.Text); end;
Assert tem como parâmetro um valor condicional (Boolean). Se falhar (False), dispara uma exceção EAssert. A vantagem é que, ao contrário de uma exceção de violação de acesso, a IDE vai te mostrar certinho onde ocorreu a violação, isto é, vai parar o debugger naquela linha do Assert. Sem uma verificação desse tipo, seria muito mais difícil identificar em todo o seu projeto o ponto que deu problema.
Se você quiser, pode ainda usar usar o segundo parâmetro opcional de Assert para dar uma mensagem ao usuário. Por exemplo: “Assert(List <> nil, ‘A função ShowText não recebeu um objeto TStringList válido’)”.
Outra vantagem do Assert é que depois que você estiver confiante da correção do código (quando esse dia chegar :) ), você poderá desativar um checkbox nas opções de compilação do Delphi para
simplesmente omitir todo o código de verificação de “Assert” globalmente no projeto (lembre-se de dar um Build depois que mudar essa opção).
Dá muito trabalho? “Better safe, than sorry.”
Que atire a primeira pedra quem nunca fez um “Access Violation”. ;-)
