Implement composite key C #

6

I'm running some tests and I've been able to implement using this form:

    public class Residencia
    {
        public object Id
        {
            get { return String.Concat(Cidade, Estado); }
            set { }
        }

        private string Cidade;
        private string Estado;

        public Residencia(string cidade, string estado)
        {
            Cidade = cidade;
            Estado = estado;
        }
    }

    private static void Main(string[] args)
    {
        List<Residencia> ListaResidencia = new List<Residencia>();
        ListaResidencia.Add(new Residencia("São Paulo", "SP"));
        ListaResidencia.Add(new Residencia("Bauru", "SP"));

        var cidade = new Residencia("Bauru", "SP");

        if (ListaResidencia.Any(x => x.Id.Equals(cidade.Id)))
        {
            Console.Write("Já existe uma Residência com esses dados.");
        }
        else
        {
            ListaResidencia.Add(cidade);
        }

        ListaResidencia.Count();

        Console.ReadKey();
    }

My question is whether this form I have implemented is correct (follows the programming standards) and if there is another way to do this (improve).

    
asked by anonymous 14.04.2014 / 14:24

2 answers

8

I do not consider this the ideal way.

.Net offers the following ways of comparing equality between two objects:

  • The virtual method Equals which can be implemented in order to compare objects with each other

  • The interface IEquatable<T> , which allows you to implement how two objects compare against each other.

  • The interface IEqualityComparer<T> allows you to implement a form of comparison for another class

Example with Equals override

public class Residencia
{
    public override bool Equals(object obj)
    {
        var other = obj as Residencia;
        if (other == null) return false;
        return this.Cidade == other.Cidade
            && this.Estado == other.Estado;
    }

    public string Cidade { get; private set; }
    public string Estado { get; private set; }

    public Residencia(string cidade, string estado)
    {
        Cidade = cidade;
        Estado = estado;
    }
}

private static void Main(string[] args)
{
    List<Residencia> listaResidencia = new List<Residencia>
    {
        new Residencia("São Paulo", "SP"),
        new Residencia("Bauru", "SP"),
    };

    var cidade = new Residencia("Bauru", "SP");

    if (listaResidencia.Contains(cidade))
    {
        Console.Write("Já existe uma Residência com esses dados.");
    }
    else
    {
        listaResidencia.Add(cidade);
    }

    listaResidencia.Count();

    Console.ReadKey();
}

Alternative using an anonimous-type

@MayogaX's comment provides an alternative, which is more like what you did. Instead of concatenating strings, you could have used an anonymous type, which would work as a perfectly composed key:

public object Id
{
    get { return new { Cidade, Estado }; }
}

And then you could use the rest of the code the way you had done it before.

Even though, I would implement the Equals method, which would change the implementation to the following:

public override bool Equals(object obj)
{
    var other = obj as Residencia;
    if (other == null) return false;
    return this.Id.Equals(other.Id);
}
    
14.04.2014 / 15:24
6

Why not use it that way?

Using a concatenation to simulate a single key is never a good idea, as it can cause ambiguity, for example:

  • Object1 = Id1: "11", Id2: "1" = > Id: "111";
  • Object2 = Id1: "1", Id2: "11" = > Id: "111";

This was a silly example, but it does serve to exemplify, of course you could create ways to prevent Ids colliding, but the code would be a bit confusing.

Why use IEquatable

Well, as our friend Miguel Angelo has previously mentioned, one solution that meets the good standard would be to use IEquatable , in addition to being a class where you can define an efficient and robust comparison method, it is an interface known to .Net and uses it in other places in the form of the project Template , for example, the Contains :

  

How would your code look?

    public class Residencia : IEquatable<Residencia>
    {
        public object Id
        {
            get { return String.Concat(Cidade, Estado); }
            set { }
        }

        private string Cidade;
        private string Estado;

        public Residencia(string cidade, string estado)
        {
            Cidade = cidade;
            Estado = estado;
        }

        public bool Equals(Residencia other)
        {
            return other != null && Estado.Equals(other.Estado) && Cidade.Equals(other.Cidade);
        }
    }

    private static void Main(string[] args)
    {
        List<Residencia> ListaResidencia = new List<Residencia>();
        ListaResidencia.Add(new Residencia("São Paulo", "SP"));
        ListaResidencia.Add(new Residencia("Bauru", "SP"));

        var cidade = new Residencia("Bauru", "SP");

        if (ListaResidencia.Any(x => x.Equals(cidade)))
        {
            Console.Write("Já existe uma Residência com esses dados.");
        }
        else
        {
            ListaResidencia.Add(cidade);
        }

        ListaResidencia.Count();

        Console.ReadKey();
    }
    
14.04.2014 / 16:24