Access object attribute passed as generic parameter

1

In my application I have a chained list class that receives a generic parameter, which will be the type of value that the list will save. In this case, which I am passing as a parameter to the Usuario class, I need to check if there already exists a Usuario registered with the registered CPF. For this, I created the Procura method, to which I inform the value that I want to compare and the attribute that I need to access, but the following error is occurring:

  

System.NullReferenceException: 'Object reference not set to   an instance of an object. '

     

System.Type.GetProperty (...) returned null.

Apparently, GetProperty() is returning null. How can I resolve this problem?

public class ListaEncadeada<T>{

    ...

    public Boolean Procura(String valor, String atributo)
    {
        var atual = cabeca;
        while (atual != null)
        {
            var obj = atual.Valor;
            String aux = obj.GetType().GetProperty(atributo).GetValue(obj).ToString();
            if (aux == valor)
            {
                return true;
            }
            atual = atual.Proximo;
        }
        return false;
    }
}

.

private void Form1_Load(object sender, EventArgs e)
{
    ...
    //verificar se já existe um usuário com o cpf informado.
    listaUsuario.Procura(valor, "cpf");
}

.

public class Usuario
{
    private String nome;
    private String cpf;
    private String senha;

    ...
 }
    
asked by anonymous 15.11.2018 / 13:33

2 answers

4

First let's combine using the correct terms. You are calling the attribute what is actually called the field . And that may have been the reason for using the wrong method of reflection. If you want to get a field, use GetField() and not the GetProperty() , a field is different from a property.

So little do I think you should change the field to a property just to be able to use the method, each has a reason to use. I will not question what is right for you in this scenario , because you do not have details of this scenario, I will only trust you you needed fields and so you used them , and now you just need to use the right reflection to get what you need.

I only put public down so I can boot easily since there is no builder (should) .

using static System.Console;

public class Program {
    public static void Main() {
        var obj = new Usuario();
        obj.nome = "João";
        WriteLine(obj.GetType().GetField("nome").GetValue(obj).ToString());
    }
}

public class Usuario {
    public string nome;
    public string cpf;
    public string senha;
}

See running on .NET Fiddle . And no Coding Ground . Also I put it in GitHub for future reference .

Another important detail: the chance that something goes wrong there is great if you make a mistake. I will not try to treat because I do not know your need, I can do something that solves the error but gives unexpected results, it can end up swallowing the error silently and worse, only you know what is appropriate.

Using reflection in C # is almost always wrong, turns the language into dynamics and passes load all disadvantages of this type of language. You are giving up the advantages of C #. Almost always has better solutions. The reflection is almost always to save the programmer's typing, which is a silly economy. It loses sturdiness and loses performance. At the very least this should be handled better if a non-existent field name comes in, which would increase code complexity and decrease performance even further. Or you can make an external tool to analyze the code statically, but then it's easier to create a code generator that gives the same result without reflection.

    
15.11.2018 / 15:17
1

Your problem is in how you declared the properties in class Usuario (or, in this case, you did not declare!), in addition to putting them all as Private , being impossible to "access" them.

If you do not put a getter and / or a setter , { get; set; } , your variables will not go beyond that, variables. In order to be effectively properties , you need to have this setting.

In this scenario the solution is to change the class Usuario to the following:

public class Usuario
{
    public string nome { get; set; }
    public string cpf { get; set; }
    public string senha { get; set; }
}

When attempting to get the value of the property, you should always be aware that one of the Get can return null , so we recommend this validation, which can be done as follows (using the conditional null and the conversion to string ):

string aux = Convert.ToString(usuario.GetType().GetProperty("cpf")?.GetValue(usuario));

In this way, the variable aux gets either the value you want or the empty string ( "" ).

    
15.11.2018 / 14:24