7
\$\begingroup\$

I'm currently working on a project where I have to map some objects to several properties.

Basically I need a Dictionary with Tuples as keys and instances of MyClass as values.

As using tuples can quickly lead to an obscure (because of item1, item2... properties) and verbose code I decided to make a class to wrap the tuples.

class Key
{
    private Tuple<string, int, int, int> _impl;

    public Key(string unitID, int address, int comPort, int id)
    {
        _impl = new Tuple<string, int, int, int>(unitID, address, comPort, id);
    }

    public override int GetHashCode()
    {
        return _impl.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return _impl.Equals(obj);
    }

    public override string ToString()
    {
        return _impl.ToString();
    }
}

That way I should take advantage of the Tuple class and avoid its inconvenients.

So I can write:

Dictionary<Key, MyClass> mapping = new Dictionary<Key, MyClass>();

Instead of:

Dictionary<Tuple<string, int, int, int>, MyClass> mapping = new Dictionary<Tuple<string, int, int, int>, MyClass>();

And look up the dictionary like this:

Key key = new Key("abc", 1, 5, 5464);
MyClass myInstance = mapping[key];

Is this implementation correct ? Is there a more proper way to achieve this ?

\$\endgroup\$

2 Answers 2

13
\$\begingroup\$
public Key(string unitID, int address, int comPort, int id)

Clearly this class represents something much more specialized than an all-purpose "key". Name the type for what it stands for!

private Tuple<string, int, int, int> _impl;

The private field should be readonly. But why don't you have this instead?

private readonly string _unitId;
private readonly int _address;
private readonly int _comPort;
private readonly int _id;
public override int GetHashCode() 
{
    return _impl.GetHashCode(); 
}

Ideally your GetHashCode implementation should rely on immutable fields. Your _impl field isn't marked readonly, which doesn't quite communicate that intent. Using actual fields and dropping the Tuple altogether, you can come up with a more standard GetHashCode implementation.

That way I should take advantage of the Tuple class and avoid its inconvenients.

You're not getting anything out the Tuple. Get rid of it, it's only obfuscating the class' implementation.


Also, you're not instantiating your Tuple the idiomatic way. This:

_impl = new Tuple<string, int, int, int>(unitID, address, comPort, id);

Should be written like this and leverage generic type parameter inference:

_impl = Tuple.Create(unitID, address, comPort, id);
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Thanks for your answer. So what should be the implementation of GetHashCode() ? I like the idea to use the Tuple implementation instead of making my own. I may also add or remove some fields in the future. So I won't have any work to do if I keep the tuple's GetHashCode() implementation. \$\endgroup\$
    – Vincent
    Commented Nov 12, 2015 at 16:30
  • 2
    \$\begingroup\$ @Vincent that's a question Jon Skeet has answered on Stack Overflow - as for the Tuple, you're basically abusing it to hold what should be private fields. This "key" class is no different from any other POCO class in your project. \$\endgroup\$ Commented Nov 12, 2015 at 16:40
  • \$\begingroup\$ +1 for noting that using the Tuple here is not contributing anything that a basic POCO couldn't handle. \$\endgroup\$
    – Nick Coad
    Commented Nov 13, 2015 at 5:31
  • \$\begingroup\$ @Mat'sMug Thanks for the link to the Jon Skeet's answer. \$\endgroup\$
    – Vincent
    Commented Nov 13, 2015 at 8:55
3
\$\begingroup\$

First off, I'd venture to say that Key is probably too generic of a name, and doesn't give much information about the type. I'd suggest the following replacements that'd give more detail:

  • TupleKeyAlias
  • FourTupleKeyAlias

I'd go with the first one, unless you can come up with a better name on your own.

In addition, rather than creating your own specialized implementation, why couldn't you have just created a subclass of Tuple<string, int, int, int>, like this:

class TupleKeyAlias 
    : Tuple<string, int, int, int>
{ }

And then just used everything that's already implemented on the Tuple class without needing to create override methods.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for your answer. Actually the class isn't named Key but something like MyClassKey. I changed the name for confidentiality concerns. By deviring the tuple class instead of wrapping it, I keep the ItemN properties. Shouldn't be better to get rid of them ? Moreover I don't need any getters or setters for this class. \$\endgroup\$
    – Vincent
    Commented Nov 12, 2015 at 16:25
  • \$\begingroup\$ @Vincent I think it's okay to keep the itemN properties, in case you ever have a need to access specific values from the tuple. \$\endgroup\$ Commented Nov 12, 2015 at 16:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.