My

Como eu já suspeitava, as classes My (disponíveis na versão 2005 do Visual Basic .NET), que são responsáveis por criar uma espécie de atalho para recursos utilizados com muita frequencia e evitar a escrita de “muito” código para uma determinada funcionalidade, na verdade apenas encapsulam códigos que já são de nosso conhecimento, como por exemplo o método ReadAllText da classe FileSystemProxy (que é na verdade um proxy para a classe FileSystem do Namespace System.IO). Para ler o conteúdo de um arquivo qualquer, podemos agora fazer simplesmente:

      Dim s As String = My.Computer.FileSystem.ReadAllText(“TextFile1.txt”)

Quando compilamos o projeto VB.NET, ele embute um Namespace chamado TeuProjeto.My, onde dentro dele, é criado classes do tipo Friend, que são vistas somente dentro daquele Assembly e uma delas chama-se MyProject. Dentro desta classe, voce terá objetos estáticos que representam os teus recursos, como por exemplo: MyApplication, MyComputer, MyForms, etc. O código é semelhante à este:

      Public Shared ReadOnly Property Application As MyApplication
      Public Shared ReadOnly Property Computer As MyComputer
      Public Shared ReadOnly Property Forms As MyForms
      Public Shared ReadOnly Property WebServices As MyWebServices

Onde para cada um desses objetos, existem também um objeto estático Read-Only, que é uma classe genérica do tipo ThreadSafeObjectProvider, que recebe qualquer um dos objetos (por isso é genérica) acima e tem a finalidade de recuperar ou criar a instância do objeto que lhe é passada:

      Private Shared ReadOnly m_AppObjectProvider As ThreadSafeObjectProvider(Of MyApplication)
      Private Shared ReadOnly m_ComputerObjectProvider As ThreadSafeObjectProvider(Of MyComputer)
      Private Shared m_MyFormsObjectProvider As ThreadSafeObjectProvider(Of MyForms)
      Private Shared ReadOnly m_MyWebServicesObjectProvider As ThreadSafeObjectProvider(Of MyWebServices)

Dentro da classe Friend MyProject, temos uma propriedade estática Read-Only para cada um de nossos recursos, que chamam a propriedade GetInstance (e se não estou enganado, usa-se a pattern Singleton para ter apenas uma única instância deste objeto) do ThreadSafeObjectProvider para o objeto em questão, no nosso caso, do MyComputer.

      Public Shared ReadOnly Property Computer As MyComputer
            Get
                  Return MyProject.m_ComputerObjectProvider.GetInstance
            End Get
      End Property

Depois da instância do objeto que queremos foi recuperada (ou criada), voltamos um pouco, ao nosso método ReadAllText da classe FileSystem, e se visualizarmos o código deste método, teremos algo bem familiar:

      Public Shared Function ReadAllText(ByVal file As String, ByVal encoding As Encoding) As String
            Dim text1 As String
            Dim reader1 As StreamReader = Nothing
            Try 
                  reader1 = New StreamReader(file, encoding, True)
                  text1 = reader1.ReadToEnd
            Finally
                  If (Not reader1 Is Nothing) Then
                        reader1.Close
                  End If
            End Try

            Return text1
      End Function

Só não consigo entender, porque um recurso tão interessante como este, não poderia também ser incorporado no C#. Talvez porque os C# developers são “gurus” demais, e ao invés de utilizar o My, criam um wrapper próprio. 😛

Update:
Há sim agora uma opção para as classes My no C#. Eis aqui a explicação.

Membros Compartilhados

Como sabemos membros compartilhados de uma classe, são membros que conseguimos acessar sem a necessidade da criação da instancia desta classe, podendo assim chamarmos o método ou propriedade e já obtemos o seu valor (ou uma Expcetion :P).

Algo que venho me atentando é que é perfeitamente possível acessar um membro compartilhado a partir de uma instancia de uma classe no VB.NET, mas no C# isso já não é possível. Independentemente disso, o código final gerado é o mesmo, ou seja, tanto o código escrito em VB.NET quanto o código escrito em C# “chamam” o membro compartilhado diretamente através da sua classe e não da instancia criada. Abaixo a prova:

[ VB.NET ]

     Public Class Teste
         Public Shared Function MeuNome() As String
             Return “Israel Aéce”
         End Function
         Public Function
Profissao() As String
             Return “Developer”
         End Function
     End Class

     Module Module1
         Sub Main()
             Dim t As New Teste
             Console.WriteLine(t.MeuNome())
             Console.WriteLine(t.Profissao())
         End Sub
     End Module

[ C# ]

      public class Teste{ 
           public static string MeuNome(){
                return “Israel Aéce”;
           }
           public string Profissao(){
                return “Developer”;
           } 
      }

      static void Main(string[] args){
           Teste t = new Teste();
           Console.WriteLine(Teste.MeuNome());
           Console.WriteLine(t.Profissao());
      }

Se fizermos o teste, veremos que nem será possível chamar o método compartilhado através de um instancia no C#, não sequer aparecendo no Intellisense, mas no VB.NET, isso é permitido pelo compilador. Finalmente o código gerado para o código acima é identico em ambas as linguagens:

      Public Shared Sub Main()
           Dim teste1 As New Teste
           Console.WriteLine(Teste.MeuNome)
           Console.WriteLine(teste1.Profissao)
     End Sub

Já que independentemente da linguagem, o código final gerado é identico, será isso um truque do compilador do VB.NET? De toda forma, não vejo motivo pelo qual a MS possibilita isso no VB.NET. Talvez porque o mesmo é considerado como uma linguagem de programação mais voltada para pessoas sem experiencia?

Parâmetros Opcionais – Inter Assemblies

Em uma aplicação qualquer, suponhamos WinForms temos um Class Library contendo as suas funções que serão utilizadas neste projeto. Em sua aplicação WinForms faz-se a referencia a este Class Library para poder consumir as funções. Algumas das funções tem um ou mais parametros opcionais, ou seja, parametros que nao precisam ser obrigatoriamente informados, mas devem ter um valor padrão. Seria algo mais ou menos como o código abaixo:

Public Class Settings
    Public Function GetInfo(Optional ByVal i As Integer = 3) As String
        Return i.ToString()
    End Function
End Class

Pois bem, agora consumindo, terei que fazer a referencia a este Class Library em minha aplicação. Feito a referencia, basta invocar o metodo:

Module Module1
    Sub Main()
        Dim x As New Settings
        Console.WriteLine(x.GetInfo())
        ‘Output: 3
        Console.ReadLine()
    End Sub
End Module

Bem, tudo ocorre como o esperado, sendo retornado o valor 3 para a aplicação. Bem, mas chega em um dia qualquer e lhe é pedido para alterar o valor padrão do teu parametro adicional, no nosso caso o parametro “i” do nosso metodo “GetInfo(…)”. Então, altera-se de 3 para 8, compila este Assembly e copia o arquivo DLL gerado para  a pasta “bin” da nossa aplicação WinForms. E qual o resultado? Por incrível que pareça, 3 novamente.

Como podem ver, mesmo copiando a nova DLL já com o novo valor, o valor não é alterado, isso porque quando compilamos a nossa aplicação, o valor padrão que informamos na assinatura do método já é passado quando invocamos o método “GetInfo(…)”. Veja como fica o Dissasembler:

<STAThread> _
Public Shared Sub Main()
      Dim settings1 As Settings = New Settings
      Console.WriteLine(settings1.GetInfo(3))
      Console.ReadLine
End Sub

Veja então agora porque mesmo alterando o nosso Class Library a nossa aplicação ainda fica com o valor “antigo”.

Tinha esta dúvida porque uma vez na lista da PontoNetPT (há algum tempo já), o meu Amigo João Paulo Carreiro havia dito que os parametros opcionais em “Inter Assemblies” eram “perigosos” e não havia entendido o porque isso. Hoje, com um tempo livre pude pedir esta explicação a ele, e realmente vi que realmente são lá um bocado perigosos.

Operadores Ternários

Estando conversando com meu amigo João Paulo Carreiro (JPC) sobre Operadores Ternários, ele me disse que ao utilizar o Operador Ternário do VB.NET (IIF) poderia ser “perigoso”, devido ao fato das duas opções serem executadas. Com isso, fiquei curioso e criei os projetos, tanto em VB.NET quanto em C# para ver o que ocorre. Abaixo os códigos em C# e VB.NET respectivamente:

[ C# ]
private System.Data.SqlClient.SqlConnection conn;
string str = (this.conn != null ? this.conn.ToString() : “Objeto esta Nulo.”);
MessageBox.Show(str);

[ VB.NET ]
Private conn As SqlClient.SqlConnection
Dim str As String = IIf(Not (Me.conn Is Nothing), Me.conn.ToString(), “Objeto esta Nulo.”)
MessageBox.Show(str)

No caso acima, no código escrito em C#, não haverá problemas pelo fato de ser realmente um Operador, e no caso do VB.NET, a falha ocorrerá, pois ele tentará retornar uma String através do método ToString() de um objeto que ainda não existe, devido ao fato de IIF ser uma função. Por isso todos os parametros devem ser executados para poderem ser passados a função, sendo assim o VB.NET não possui um operador ternário. Ao fazer o Disassembler do método IIF, temos o seguinte código:

Public Shared Function IIf(ByVal Expression As Boolean, ByVal TruePart As Object, ByVal FalsePart As Object) As Object 
    Dim obj1 As Object
    If Expression Then
        Return TruePart 
    End If
    Return FalsePart 
End Function

Agora fica claro o porque antes de chamado esta função, deve ser executado e-ou formatado os valores. Com isso vemos que independentemente da condição ser ou não atendida, as duas opções serão executadas. Para talvez “consertar” o código em VB.NET, temos que ter o objeto realmente criado:

Private conn As SqlClient.SqlConnection
Dim str As String
If Not (Me.conn Is Nothing) Then str = Me.conn.ToString() Else str = “Objeto esta Nulo.”
MessageBox.Show(str)

Ou até mesmo:

Private conn As SqlClient.SqlConnection
Dim str As String
If Not (Me.conn Is Nothing) Then
    str = Me.conn.ToString()
Else
    str = “Objeto esta Nulo.”
End If
MessageBox.Show(str)

Bem, fica aqui a dica para que se precisarem utilizar o “Operador Ternário” do VB.NET, fiquem atentos para não cairem nessa “armadilha”. 😉

Essas coisas me irritam :(

Puxa, sem dúvida a Microsoft “caprichou” na plataforma .NET.

Não vou ficar falando aqui os benefícios que ele nos trouxe, senão, não acabaria este fim de semana. 🙂

E agora vendo em um post pela internet, vi um rapaz dizendo que VB.NET não é Orientado à Objetos porque não tem Herança Múltipla. Quando era/é VB6 diziam que ele não era/é Orientado à Objetos porque não tinha Herança (até aí, talvez até faça sentido), mas falar que VB.NET não é, aí já é brincadeira. 😐

Sempre encontram algum motivo para criticar a Microsoft e seus produtos. Será que ninguém se rende à ela?!?