Comparing two objects and copying conditionally

Asked

Viewed 84 times

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 with the values of Pessoal, but only how much value of the PessoalAlteracao is equal to null.

I can do through a if:

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

But I would like to use a simpler form, I would like to create a loop, by attributes and match testing values?

2 answers

4

The simplest way is this:

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

I put in the Github for future reference.

All other options are more complicated. Some may have fewer lines (for few properties it is not), but become more complex to do, may have difficulties in certain scenarios (it only works if clone everything at the same criteria, which may not be true today, or it may not 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 an overridable type for this, which would pollute the object with something unnecessary just to suit a mechanism that allows the programmer to type fewer lines. Either it goes wrong or the concept is wrong and will charge one day for it.

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

Almost every reflection used in C# is unnecessary.

It’s obvious that if the object is usually cloned like this it makes sense to put it in a method and not keep creating code to clone everywhere you use it.

I didn’t even ask if you need to make this filter null or not. It might not need to, then it would be enough to clone in a standard way, even if it would use reflection as well, but it would not need to write its own code.

  • ♦ It would not be a clone, as one class the original data and other data changed (corrected) by the user. Then be null need to be equal (clone), otherwise I need to hide what was informed by the user. Thank you for the clarification.

  • @Jota is a conditional cloning, but it’s a cloning. I edited to show you more that it doesn’t work to automate this.

  • I have come across projects that abuse Pattern or complicate architecture in excess, and a simple approach would solve. The idea really was to create a simplified code, but I understood your point of view, that there is no such thing as a free lunch. And everything must be measured and weighed the pros and cons.

3


It is possible to do using reflection (Reflection).

Keep in mind that although this greatly shortens the code, it may have a slower execution than simply writing "in hand" property by property or using any other approach.

Depending on how the classes are going and the general rule for this value substitution, a clone would be a slightly better choice - even if it is still made use of reflection. 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);
    }           
}

Full 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 on . NET Fiddle

  • I think that new pessoal and not of alteracao

  • 1

    @Rovannlinhalis it is. I’ll improve the answer soon. I’m having lunch now, when I get back adjusted. Thank you.

  • @LINQ are about 60 fields and so I think in case the Reflection will be able to be used and will facilitate the coding, because it is only a basic change screen. I will test here to see if it will impact the performance, but I do not think so. Thank you very much for your patience and help with great quality teaching.

  • @Jota For nothing. Not always Reflection is a monster, for specific cases it is very useful. Good luck there =)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.