Desenvolvimento - C#
.Net Framework Inside : Reflection e Construtores
Este artigo mostra como trabalhar os Contrutores dos Objetos com Reflection.
por Guilherme Bacellar MoralezIremos começar a utilizar reflexão, para tanto, vamos adotar uma classe modelo para que possamos ter controle sobre a utilização:
C#
namespace ReflectionCSharp
{
/// <summary>
/// Classe de Usuário de Exemplo
/// </summary>
[Serializable]
[XmlRoot("Usuário")]
public class Usuario : System.Object, IComparable<Usuario>, INotifyPropertyChanged
{
#region Construtores
public Usuario() { }
public Usuario(string nome, int idade, DateTime dataNascimento)
{
_Nome = nome;
_Idade = idade;
_DataNascimento = dataNascimento;
}
#endregion
#region Fields (Campos)
private string _Nome;
private int _Idade;
private DateTime _DataNascimento;
#endregion
#region Propriedades
[XmlAttribute("Nome")]
public string Nome
{
get { return _Nome; }
set { _Nome = value; }
}
public int Idade
{
get { return _Idade; }
set { _Idade = value; }
}
[XmlElement("DataNascimento")]
public DateTime DataNascimento
{
get { return _DataNascimento; }
set { _DataNascimento = value; }
}
#endregion
#region Eventos
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Implementações dos Métodos das Interfaces Declaradas
/// <summary>
/// Método da Interface IComparable
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public int CompareTo(Usuario other)
{
// Realiza Comparação de Nome
return this.Nome.CompareTo(other.Nome);
}
#endregion
#region Métodos
/// <summary>
/// Calcula a Idade do Usuário pela Data do Nascimento
/// </summary>
/// <returns></returns>
public int CalculaIdade()
{
// Chama o Método Privado Estático desta Classe
return CalculaIdade(this.DataNascimento);
}
/// <summary>
/// Calcula a Idade do Usuário pela Data do Nascimento passada por Parâmetro
/// </summary>
/// <returns></returns>
private static int CalculaIdade(DateTime dataNascimento)
{
TimeSpan result = DateTime.Now.Subtract(dataNascimento);
return (int)(result.TotalDays / 365);
}
#endregion
}
}
VB.Net
Namespace ReflectionVBNet
""" <summary>
""" Classe de Usuário de Exemplo
""" </summary>
""" <remarks></remarks>
<Serializable()> _
<XmlRoot("Usuário")> _
Public Class Usuario
Implements INotifyPropertyChanged, IComparable(Of Usuario)
#Region "Construtores"
Public Sub New()
End Sub
Public Sub New(ByVal nome As String, ByVal idade As Int32, ByVal dataNascimento As DateTime)
_Nome = nome
_Idade = idade
_DataNascimento = dataNascimento
End Sub
#End Region
#Region "Fields (Campos)"
Private _Nome As String
Private _Idade As Integer
Private _DataNascimento As DateTime
#End Region
#Region "Propriedades"
<XmlAttribute("Nome")> _
Public Property Nome() As String
Get
Return _Nome
End Get
Set(ByVal value As String)
_Nome = value
End Set
End Property
Public Property Idade() As Integer
Get
Return _Idade
End Get
Set(ByVal value As Integer)
_Idade = value
End Set
End Property
<XmlElement("DataNascimento")> _
Public Property DataNascimento() As Date
Get
Return _DataNascimento
End Get
Set(ByVal value As Date)
_DataNascimento = value
End Set
End Property
#End Region
#Region "Eventos"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
#End Region
#Region "Implementações dos Métodos das Interfaces Declaradas"
""" <summary>
""" Método da Interface IComparable
""" </summary>
""" <param name="other"></param>
Public Function CompareTo(ByVal other As Usuario) As Integer Implements IComparable(Of Usuario).CompareTo
Return Me.Nome.CompareTo(other.Nome)
End Function
#End Region
#Region "Métodos"
""" <summary>
""" Calcula a Idade do Usuário pela Data do Nascimento
""" </summary>
""" <returns></returns>
""" <remarks></remarks>
Public Function CalculaIdade() As Integer
"" Chama o Método Privado Estático desta Classe
Return CalculaIdade(Me.DataNascimento)
End Function
""" <summary>
""" Calcula a Idade do Usuário pela Data do Nascimento passada por Parâmetro
""" </summary>
""" <remarks></remarks>
Private Function CalculaIdade(ByVal dataNascimento As DateTime) As Integer
Dim result As TimeSpan = DateTime.Now.Subtract(dataNascimento)
Return CType((result.TotalDays / 365), Int32)
End Function
#End Region
End Class
End Namespace
Essa classe foi criada para que possamos trabalhar de forma controlada com Reflection e também foi desenhada para conter todos os itens que podemos precisar para nosso estudo sobre Reflection.
Recuperando todos os Construtores
A recuperação de construtores com Reflection permite que possamos criar as instâncias de nossos objetos utilizando os recursos já implementados nos construtores.
Para tanto, utilizaremos o método (GetConstructors) do tipo desejado.
C#
// Cria Objetos
Type meuTipo;
ConstructorInfo[] constructors;
// Recupera o Tipo Desejado
meuTipo = typeof(Usuario);
// Recupera os Construtores
constructors = meuTipo.GetConstructors();
VB.Net
" Cria Objetos
Dim meuTipo As Type
Dim constructors As ConstructorInfo()
" Recupera o Tipo Desejado
meuTipo = GetType(Usuario)
" Recupera os Construtores
constructors = meuTipo.GetConstructors()
Desta forma temos uma coleção dos construtores que definem nosso objeto. Neste caso, nossa classe (Usuario) possui 2 construtores.
Recuperando um (01) Construtor Específico
Na maioria das situações precisaremos recuperar apenas 1 construtor específico e não todos eles.
Neste caso, utilizamos o método (GetConstructor) do tipo desejado.
C#
// Cria Objetos
Type meuTipo;
ConstructorInfo parameterLessConstructor;
ConstructorInfo parameterizedConstructor;
// Recupera o Tipo Desejado
meuTipo = typeof(Usuario);
// Recupera o Construtor sem Parâmetros
parameterLessConstructor = meuTipo.GetConstructor(new Type[]{});
// Recupera o Construtor com o Nome (string), Idade (int) e Data do Nascimento (DateTime)
parameterizedConstructor = meuTipo.GetConstructor(new Type[] {typeof (string), typeof (int), typeof (DateTime)});
VB.Net
" Cria Objetos
Dim meuTipo As Type
Dim parameterLessConstructor As ConstructorInfo
Dim parameterizedConstructor As ConstructorInfo
" Recupera o Tipo Desejado
meuTipo = GetType(Usuario)
" Recupera o Construtor sem Parâmetros
parameterLessConstructor = meuTipo.GetConstructor(New Type() {})
" Recupera o Construtor com o Nome (String), Idade (Integer) e Data do Nascimento (DateTime)
parameterizedConstructor = meuTipo.GetConstructor(New Type() {GetType(String), GetType(Integer), GetType(DateTime)})
Perceba que, o método (GetConstructor) “como quase todos os métodos que recuperam informações por Reflection” responde a assinatura do elemento desejado.
Então, em nosso caso, passando-se uma lista de “Tipos” vazia temos como resposta um Construtor sem parâmetros. Mas, se passarmos uma lista de “Tipos” os “Tipos” dos parâmetros obteremos de retorno o elemento que atende à assinatura dos “Tipos” especificados.
Esse conceito é muito importante na Reflexão, então, vamos guardá-lo.
E se os Construtores não forem Públicos?
Até agora está tudo fácil, mas, e se o construtor não for público?
Se por acaso, o construtor de nosso objeto (Usuario) não fosse público, o método acima retornaria nulo/nothing como resultado da recuperação do construtor.
Contudo, o mecanismo de Reflexão do .NET é extremamente poderoso e permite que recuperaremos membros “não públicos” dos objetos.
C#
// Cria Objetos
Type meuTipo;
ConstructorInfo parameterLessConstructor;
// Recupera o Tipo Desejado
meuTipo = typeof(Usuario);
// Recupera o Construtor sem Parâmetros
parameterLessConstructor = meuTipo.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[]{}, null);
VB.Net
" Cria Objetos
Dim meuTipo As Type
Dim parameterLessConstructor As ConstructorInfo
" Recupera o Tipo Desejado
meuTipo = GetType(Usuario)
" Recupera o Construtor sem Parâmetros
parameterLessConstructor = meuTipo.GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, New Type() {}, Nothing)
Observemos o método (GetConstructor) com mais parâmetros. Dentre eles existem as BindingFlags, que permitem a mudança do escopo da Reflexão. Em nosso exemplo estamos pedindo por membros “não públicos” e “de instância”.
Observe os outros parâmetros nulos. Eles são para especificar-mos um “Binder” customizado, e modificadores de parâmetros. Não vamos entrar neles neste momento, mas, em breve vamos explicar-los em detalhes.
Sendo assim, obtemos um construtor sem parâmetros (observem o “Tipo” vazio) e que ao mesmo tempo é privado.
Este também é outro conceito muito importante do mecanismo de Reflection.
Construindo Classes
Bom, tudo isso para que possamos construir uma classe, então, vamos lá.
Nosso objeto “ConstructorInfo” contém um método chamado “Invoke” que ativa seu funcionamento, então....
C#
// Cria Objetos
Usuario novoUsuarioSemParametros;
Usuario novoUsuarioComParametros;
// Cria Novo Usuário com o Construtor sem os Parâmetros
novoUsuarioSemParametros = (Usuario)parameterLessConstructor.Invoke(null);
// Cria um Novo Usuário com o Contrutor com os 3 Parâmetros
novoUsuarioComParametros = (Usuario)parameterizedConstructor.Invoke(new object[] { "Guilherme Bacellar Moralez", 25, new DateTime(1982, 10, 12) });
VB.Net
" Cria Objetos
Dim novoUsuarioSemParametros As Usuario
Dim novoUsuarioComParametros As Usuario
" Cria Novo Usuário com o Construtor sem os Parâmetros
novoUsuarioSemParametros = CType(parameterLessConstructor.Invoke(Nothing), Usuario)
" Cria um Novo Usuário com o Contrutor com os 3 Parâmetros
novoUsuarioComParametros = CType(parameterizedConstructor.Invoke(New Object() {"Guilherme Bacellar Moralez", 25, New DateTime(1982, 10, 12)}), Usuario)
Conseguimos criar novos objetos (Usuario) com o construtor sem parâmetros e com o construtor com parâmetros.
Para finalizar, observe que o método (Invoke) recebe uma coleção de (Objetos) com os parâmetros desejados para a ativação do construtor.
Bom, de Construtores com Reflexão é só.
Até o próximo artigo sobre Reflexão.