Сравнение универсального типа со значением по умолчанию без ограничения универсального класса дает ошибку времени компиляции - PullRequest
8 голосов
/ 03 сентября 2010

Я только что столкнулся с этой ситуацией и подумал, что это хорошая возможность использовать ключевое слово по умолчанию. Но это не компилируется, и я не могу понять, почему. Пример ниже иллюстрирует мою проблему:

public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result != default(TDataSource);
    }
}

Вы получите ошибку в строке 8 («Оператор '==' не может быть применен к операндам типа« TDataSource »и« TDataSource ».»). Я думал, что использование ключевого слова по умолчанию устранит любые проблемы сравнения между ссылочными типами и типами значений.

Добавление общего ограничения, ограничивающего TDataSource для ссылочных типов, делает этот фрагмент кода компилируемым.

Может кто-нибудь объяснить, почему компилятор не исправит это для меня? Разве это не достаточно умно, чтобы увидеть, что это сработает?

Это связано: Не может ли оператор == применяться к универсальным типам в C #?

[Изменить] Ответ SLaks дал мне некоторое вдохновение, оператор '==' не будет работать, но функция Equals должна.

    public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result.Equals(default(TDataSource));
    }
}

Компилирует ли эта функция правильно?

1 Ответ

6 голосов
/ 03 сентября 2010

Вы не можете предполагать, что каждый тип значения переопределяет оператор ==.(И даже если бы они это сделали, не было бы способа вызвать его с помощью обобщений; это статический метод)

Вместо этого вы должны написать

    return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
          || result.Equals(default(TDataSource)));

Если result равно null (и ссылочный тип), вызов ReferenceEquals вернет true, поэтому Equals не будет вызван и не выдаст NullReferenceException.
Если TDataSource является типом значения,ReferenceEquals будет сравнивать две разные ссылки в штучной упаковке (которые могут содержать одно и то же значение, но все равно будут разными), поэтому он передается на вызов Equals.

...