quinta-feira, 30 de dezembro de 2010

Sabe o que é modificador internal? Sabe mesmo???

Pois é, o post começa com algo bem básico do C#, coisa do primeiro dia de aula mesmo: Modificadores de Acesso. Só pra relembrar:

  • public : Sem restrição de acesso.
  • protected : Acessado pela classe que o define e pelas classes derivadas dela.
  • internal : Acessado apenas de dentro do mesmo assembly.
  • private : Acessado somente de dentro da classe (mesmo se forem instancias diferentes).

Isso todo mundo já sabe (ou deveriam saber). O ponto em que quero chegar é que, dizer que "membros ou tipos internal só podem ser acessados dentro do mesmo assembly" não é uma completa verdade.

InternalsVisibleToAttribute

O atributo InternalsVisibleTo introduz ao assembly o conceito de Friend Assembly. Com isto os membros ou tipos marcados com o modificador de acesso internal podem ser acessados de outro assembly. Vamos ver como funciona:

Nesta solução podemos ver que existem 3 Projetoprojetos, sendo 2 projetos do tipo ClassLibrary e 1 ConsoleApplication.

Adicionamos o projeto AssemblyA como referencia no projeto MyConsoleApplication. Depois o projeto AssemblyB como referencia no projeto AssemblyA e MyConsoleApplication.

Ele ficará como a imagem ao lado. Podemos ver que existem algumas classes já declaradas.

No AssemblyB temos uma classe com modificador de acesso internal e outra com o modificador de acesso public (Como dizem os nomes).

Agora vamos tentar instanciar a classe AssemblyB.MyInternalClass de dentro da cBuild Faillasse AssemblyA.MyPublicUtilClass e compilar a aplicação para ver o que acontece.

O Visual Studio não deixa compilar a aplicação. Ele nos mostra o motivo do build failed em duas mensagens de erro:

  1. O tipo AssemblyB.MyInternalClass não tem construtor definido.
  2. O tipo AssemblyB.MyInternalClass não é acessível devido ao seu nível de proteção.

Como a classe está definida com o seu modificador de acesso sendo internal o Visual Studio segue a regra que descrevemos mais acima e não deixa ela ser acessada (no caso instanciada).

Esses mesmos dois erros ocorreriam se tivéssemos tentado o acesso a esta classe no assembly MyConsoleApplication.

Nesse momento entra em ação o atributo InternalsVisibleTo que faz uma alteração a nível de assembly fazendo com que AssemblyA possa instanciar a classe em questão.

Segue o trecho que pode ser colocado em qualquer arquivo de código mas que por boas práticas deve ser colocado no arquivo AssemblyInfo da pasta Properties do projeto.

AssemblyInfo

Com isto compilamos novamente a aplicação e podemos ver que agora temos acesso a classe MyInternalClass de dentro do assembly AssemblyA.

Também podemos verificar que apesar do acesso a classe MyConsoleApplicationMyInternalClass ter sido alterado em relação ao assembly AssemblyA, o assembly MyConsoleApplication ainda continua ser ter acesso. Se fosse necessário que o assembly MyConsoleApplication pudesse acessar também a classe MyInternalClass bastaria colocar mais um atributo (permite múltiplos) no AssemblyInfo especificando isto.

Considerações Importantes

Não são muitos os casos onde é aconselhada esta prática. Ela é exigida em casos onde a organização do projetoSistem.Workflow.Activities a exige:

  • Casos onde existe um projeto de teste e é necessário o acesso a membros internal para o teste.
  • Quando se desenvolve um ClassLibrary que é composto por vários assemblies mas requerem acesso a membros existentes entre eles. Este é o caso do assembly System.Workflow.Activities.

O exemplo que implementei foi o de mais fácil compreensão. Existem algumas regras que devem ser seguidas para a utilização desde atributo. A regra mais importante é a respeito dos Strong Names:

  • Se o assembly que se quer ter os membros internal visíveis tiver um strong name o assembly que o consumirá também deverá ter. No atributo InternalsVisibleTo deverá constar, separados por vírgula, o nome do assembly mais a public key dentro da string que é passada ao construtor.
  • Se o assembly que se quer ter os membros internal visíveis não tiver um strong name o assembly que o consumirá também não deverá ter.

Enjoy

sexta-feira, 24 de dezembro de 2010

Imitando efeito 3D no Silverlight

Introduzidos na versão 3 do Silverlight os efeitos de projeção (Projection) podem passar desapercebidos como se fossem reais efeitos 3D.silverlight-logo

Na verdade o que acontece é que o Silverlight traduz o objeto de projeção em formas matemáticas que aplicadas nas transformações de layout fazem com que elementos pareçam 3D.

Jeff Prosise mostra neste artigo da MSDN que é possível até mesmo na versão 2 do Silverlight apenas usando RenderTransform.

Mas a minha ideia hoje é mostrar do jeito mais fácil, sem todos esses cálculos e tal. Então vamos direto ao assunto.

UIElement.Projection

A propriedade Projection é onde vamos trabalhar. Nela podemos ver várias propriedades que irão afetar a renderização final de um elemento de interface.

Esta propriedade é do tipo System.Windows.Media.Projection que é uma classe abstrata. Até hoje existem duas implementações concretas no Silverlight: PlaneProjection e Matrix3DProjection.

A Matrix3DProjection permite que se escreva detalhadamente a matriz 3D que se quer desenhar, dificultando um pouco para quem não tem grandes noções do assunto.

Já a PlaneProjection permite que possamos definir um grupo de 12 propriedades de fácil entendimento. São elas:

Digamos que seja 3D for newbies.

Vamos começar com um exemplo bem simples. Vamos girar um border 45 graus nos eixos x e y e z com o código abaixo (resumido):

<Border Name="border1"> <Border.Projection> <PlaneProjection RotationY="45" RotationX="45" RotationZ="45" /> </Border.Projection> <TextBox Text="Para Cima"> </TextBox> </Border>

E o resultado podemos conferir na imagem logo abaixo:

Primeiro exemplo

Coloquei um texto dentro só para termos um ideia de como o efeito é transmitido para os elementos filhos. Também podemos notar que o TextBox continua 100% funcional.

Mas não para por aí. A classe PlaneProjection tem várias DependencyProperties e isso quer dizer que podemos fazem Binding com elas.

Além disso também podemos aplicar animações a essas propriedades aumentado ainda mais o nível de experiência do usuário.

No exemplo abaixo Neste exemplo você pode clicar no botão para ver a animação nos controles em ação. Também pode alterar os valores dos Sliders alterando a posição da caixa vermelha.

Isso é só uma pequena demonstração do que pode ser feito. Tente em casa.

Aqui está o código fonte deste exemplo. E não, eu não me preocupei com o layout, só em passar o conhecimento. Este blog não e de Design. =D

Enjoy