Неявное приведение объекта к строке для использования в Hashtable - PullRequest
6 голосов
/ 07 марта 2012

Допустим, у нас есть этот класс:

public class Moo
{
    string _value;

    public Moo(string value)
    {
        this._value = value;
    }

    public static implicit operator string(Moo x)
    {
        return x._value;
    }

    public static implicit operator Moo(string x)
    {
        return new Moo(x);
    }

    public override bool Equals(object obj)
    {
        if (obj is string)
            return this._value == obj.ToString();
        else if (obj is Moo)
            return this._value == ((Moo)obj)._value;
        return base.Equals(obj);
    }

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

Если я добавлю объект этого типа в Hashtable, тогда я смогу найти объект с помощью идентичной строки.
Но если Hashtable содержит строку, а не объект, он не может найти ее, когда я передаю объект.

Moo moo = new Moo("abc");
bool result1 = moo == "abc";                    //true
bool result1a = moo.Equals("abc");              //true
bool result2 = "abc" == moo;                    //true
bool result2a = "abc".Equals(moo);              //true
bool result2b = ((object)"abc").Equals(moo);    //false

Hashtable hash = new Hashtable();
hash[moo] = 100;
object result3 = hash[moo];                     //100
object result4 = hash["abc"];                   //100

hash = new Hashtable();
hash["abc"] = 100;
object result5 = hash[moo];                     //null!!!!
object result6 = hash["abc"];                   //100

Я пытался переопределить оператор ==, и это не имело значения.
Можно ли таким образом использовать неявное приведение в Hashtable?

Ответы [ 2 ]

5 голосов
/ 07 марта 2012

Во-первых, почему вы используете хеш-таблицу, а не универсальный Dictionary<,>?

Несмотря на это, ваша проблема в том, что хеш-таблица вызывает ((object)"abc").Equals(moo), что, конечно, возвращает false. Вы можете переопределить это поведение, передав собственную реализацию IEqualityComparer одному из конструкторов HashTable с параметром IEqualityComparer.

Поскольку, как вы заметили, вы пытаетесь избежать изменения унаследованного кода, возможно, вам не удастся заменить существующую хеш-таблицу на другую, имеющую собственный IEqualityComparer. Если это правда, то я думаю, что ответ в том, что вы не можете делать то, что хотели бы.

Поскольку вы разрабатываете этот класс "moo", я предполагаю, что вы имеете контроль над кодом, который передает класс moo индексатору хеш-таблицы. Если это так, вы можете просто вызвать ToString() для объекта, который вы передаете индексатору, и, конечно, переопределить ToString в Moo.

4 голосов
/ 07 марта 2012

Так что неявные приведения здесь не имеют значения.Они ничего не сделают.Вы получите точно такие же результаты, если вы закомментируете их.Здесь важны методы Equals и GetHashCode.

Так что с вашим методом GetHashCode все в порядке.Два объекта (будь то строка или moo) всегда будут иметь одинаковый хеш, если они должны быть одинаковыми, поэтому он будет работать.Ваша проблема в методе equals.

moo.Equals("abc") вернет true.

object obj = moo;
"abc".Equals(obj)

вернет false;"abc".Equals(moo) вернет true только потому, что существует неявный оператор, который преобразует moo в строку и использует перегрузку строки Equals, а не перегрузку объекта Equals.Поскольку Hashtable будет хранить все как объект, он всегда будет использовать перегрузку object метода Equals.(Оператор == не используется; он использует метод Equals в словаре.) Это связано с тем, что метод Equals строки проверяет, является ли переданный объект строкой, и возвращает false, еслиего нет.

Решение: вам не нужно использовать конструктор по умолчанию HashTable.Вам нужно использовать пользовательский IEqualityComparor, чтобы он не использовал метод Equals самого объекта.Это не так уж сложно сделать.Просто создайте новый класс, который расширяет IEqualityComparer, и присвойте ему метод equals, который в основном совпадает с методом Equals вашего moo, чтобы он правильно выполнял сравнение, независимо от того, какой тип объекта он использует.

...