Вопрос

Я хочу написать общую функцию, которая имеет ограничение на типе. В частности, я хочу что-то вроде этого:

bool IsInList<T>(T value, params T[] args)
{
    bool found = false;
    foreach(var arg in args)
    {
        if(arg == value)
        {
            found = true;
            break;
        }
    }
    return found;
 }

В том, что вы можете проверить, находится ли элемент в списке параметров Viz:

if(IsInList("Eggs", "Cheese", "Eggs", "Ham"))

Тем не менее, компилятор кроки на линии равенства. Поэтому я хочу поставить в ограничение на то, что он реализует iвателю. Однако ограничения, кажется, работают только на уровне класса. Это правильно, или есть какой-то способ уточнить это в общем?

Это было полезно?

Решение

Общие ограничения работают на общих методах:

bool IsInList<T>(T value, params T[] args) where T : IEquatable<T>

НО, IEquatable<T> не определяется operator ==, Только Equals(T).

Итак, вы должны использовать Equals() И вам даже не нужно ограничение для этого: Equals(object) является членом object.

Также не забывайте, что Equals не будет работать, если объект null.

Другие советы

Другие упомянули IEquatable<T> что, безусловно, является хорошим потенциальным ограничением.

Другой вариант, чтобы запомнить EqualityComparer<T>.Default, который будет использовать IEquatable<T> если доступно, но вернуться к object.Equals(object) иначе. Это означает, что вы можете использовать его с типами, которые предписывают дженерики, но переопределить Equals, Например:

bool IsInList<T>(T value, params T[] args)
{
    IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
    bool found = false;
    foreach(var arg in args)
    {
        if(comparer.Equals(arg, value))
        {
            found = true;
            break;
        }
    }
    return found;
}

Обратите внимание, что компактность по умолчанию равноправие также справляется с нулевыми ссылками, поэтому вам не нужно беспокоиться о том, что они сами. Если тип T не перекрыл object.Equals(object) или реализован IEquatable<T>, вы получите семантику ссылочного равенства (то есть это вернется только true Если точная ссылка находится в массиве).

Несколько других моментов:

  • Ваше желание придерживаться одной точки выхода делает код менее читаемым, IMO. Здесь нет необходимости в дополнительной переменной:

    bool IsInList<T>(T value, params T[] args)
    {
        IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
        foreach (var arg in args)
        {
            if (comparer.Equals(arg, value))
            {
                return true;
            }
        }
        return false;
    }
    
  • LINQ уже содержит метод для этого, Contains, Таким образом, вы можете упростить код:

    bool IsInList<T>(T value, params T[] args)
    {
        return args.Contains(value);
    }
    
  • Array Эффективно содержит эту функциональность тоже с IndexOf:

    bool IsInList<T>(T value, params T[] args)
    {
        return Array.IndexOf(args, value) != -1;
    }
    
  • Ваш метод, возможно, немного вводит в заблуждение имени, учитывая, что args это массив, а не List<T>.

Оператор `== 'обычно используется только для неизменных типов - (встроенные типы значений или пользовательские неизменные типы, которые перегружены оператором ==. Если вы не перегружете его, если вы используете его на ссылочных типах, (кроме строк) Возвращает только True, если оба переменных указывают на один и тот же экземпляр типа (тот же объект). Это вернет ложь, если две свергирующие данные имеют разные экземпляры типа, даже если они оба имеют все те же внутренние значения данных.

Таким образом, вам нужно ограничить тип t на эти типы, которые реализуют Equals() Функция, которая предназначена для определения того, являются ли два экземпляра любого типа «равны», а не только что они оба указывают на тот же экземпляр ... и использовать это вместо этого. Встроенный интерфейс IEquatable<T> выражает это для вас. (Вроде как нравится IComparable<T> требует, чтобы тип имеет CompareTo() Функция)
Кроме того, вы можете сделать вашу функцию большим количеством Терсера и понятнее ...

попробуй это:

bool IsInList<T>(T value, params T[] args) where T:IEquatable<T>
{ 
    foreach(var arg in args)          
        if(value.Equals(arg)) return true;
    return false;
 } 

Вы также должны понимать разницу между COVALL () и == и решить, что более подходит для того, чтобы все, что ваше намерение ... проверить это Ссылка для получения дополнительной информации.

Просто заменить

arg == value

с участием

arg.Equals(value)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top