Comparing two objects and copying conditionally

1

I have the following classes:

public class Pessoal
{
    public int ID { get; set; }
    public string CPF { get; set; }
    public string PIS { get; set; }
    public string NOME { get; set; }
    ...
    ...
    ... 
}


public class Dominio : DominioBase
{

    public Pessoal Pessoal { get; set; }

    public Pessoal PessoalAlteracao { get; set; }

}   

I would like to copy the attributes of PessoalAlteracao to the values of Pessoal , but only how much value of the PessoalAlteracao attribute is equal to null .

I can do this through if :

PessoalAlteracao.CPF = PessoalAlteracao.CPF == null ? Pessoal.CPF : PessoalAlteracao.CPF;

But I would like to use a simpler form, how would I create a loop , by the attributes and even test the values?

    
asked by anonymous 16.10.2017 / 15:45

2 answers

3

You can do this using reflection .

Keep in mind that while this will greatly shorten the code, it may have a slower execution than simply typing "in-hand" property by property or using another approach.

Depending on how the classes are and the general rule for this value substitution, a clone would be a slightly better choice - even if reflection is still used. But it is not possible to say anything without knowing the scenario better.

var pessoal = dominio.Pessoal;
var alteracao = dominio.PessoalAlteracao;

foreach(var prop in alteracao.GetType().GetProperties()) 
{
    if(prop.GetValue(alteracao, null) == null)
    {
        var novoValor = alteracao.GetType().GetProperties().First(p => p.Name == prop.Name)
                                 .GetValue(pessoal, null);
        prop.SetValue(alteracao, novoValor);
    }           
}

Complete example

using System;
using System.Linq;

public class Program
{
    static Dominio _dominio = new Dominio
    {
        Pessoal = new Pessoal
        {
            ID = 1,
            CPF = "033",
            PIS = "123",
            NOME = "João"
        },

        PessoalAlteracao = new Pessoal
        {
            ID = 1,
            PIS = "987"
        }
    };

    public static void Main()
    {
        var pessoal = _dominio.Pessoal;
        var alteracao = _dominio.PessoalAlteracao;

        foreach(var prop in alteracao.GetType().GetProperties()) 
        {
            if(prop.GetValue(alteracao, null) == null)
            {
                var novoValor = alteracao.GetType().GetProperties()
                                .First(p => p.Name == prop.Name).GetValue(pessoal, null);
                prop.SetValue(alteracao, novoValor);
            }           
        }

        foreach(var prop in alteracao.GetType().GetProperties()) 
        {
           Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(alteracao, null));
        }

    }
}

public class Pessoal
{
    public int ID { get; set; }
    public string CPF { get; set; }
    public string PIS { get; set; }
    public string NOME { get; set; }
}

public class Dominio
{
    public Pessoal Pessoal { get; set; }
    public Pessoal PessoalAlteracao { get; set; }

}

See working in .NET Fiddle

    
16.10.2017 / 15:57
4

The simplest way is this:

PessoalAlteracao.CPF = PessoalAlteracao.CPF ?? Pessoal.CPF;

Too bad that syntax does not allow this:

PessoalAlteracao.CPF ??= Pessoal.CPF;

All other options are more complicated. Some may have fewer rows (for a few properties it is not), but become more complex to do, may have difficulties in certain scenarios (only works if you clone everything in the same criteria, which may not be true today, or may no longer be tomorrow) and the performance suffers.

Note that the adopted criterion does not work for types by value, and must have several. Unless you use a nullable type for this, which would pollute the object with something unnecessary just to fit a mechanism that allows the programmer to enter fewer rows. Either it gives the wrong result or the concept is wrong and it will charge one day for it.

I would not use reflection in C # until it's absolutely necessary. When you start abusing this feature it is because C # is the wrong language for this project.

Almost every reflection used in C # is unnecessary.

Obviously, if the object is usually cloned so it makes sense to put this into a method and not be creating code to clone everywhere you use it.

I did not even wonder if you need to do this filter if it is null or not. You might not need to clone it by default, but you'd use reflection too, but you would not even need to write your own code.

    
16.10.2017 / 16:49