поиск в словаре возвращает неожиданное значение

#c#

#c#

Вопрос:

у меня есть несколько объектов, у каждого объекта есть точка, я создал для нее словарь (я не уверен, что это лучшая практика), теперь я хочу получить точку на основе значения, вот что я сделал

   var x = new Dictionary< EnemisEntity,int>()
   {

       {new EnemisEntity{enemyType="banzai_Bill"},200 },
       {new EnemisEntity{enemyType="beach_koopa" },400 },
       {new EnemisEntity{enemyType="big_boo"},800 },
       {new EnemisEntity{enemyType="blargg"},1600 },

   };
        var m= x.FirstOrDefault(f => f.Key.Equals("big_boo")).value;
  

я должен вернуть мне 800, но это дает мне 0, не могли бы вы, пожалуйста, сказать мне, прежде всего, правильно ли я поступаю, и, во-вторых, почему это дает мне ноль

Комментарии:

1. @BradleyUffner могу я спросить о преимуществе?

Ответ №1:

Вы можете изменить свой код на:

 var m = x.FirstOrDefault(f => f.Key.enemyType.Equals("big_boo")).Value;
  

В вашем выражении фильтра f => f.Key.Equals("big_boo") f a KeyValuePair имеет Key тип EnemisEntity , поэтому сравнение его со строкой with object.Equals дает вам false и FirstOrDefault возвращает значение по умолчанию KeyValuePair<EnemisEntity, int> , которое представляет собой структуру со Value свойством, инициализированным значением default int 0 .

Без дополнительного контекста (как используется этот словарь) трудно утверждать, какой дизайн будет более подходящим, другими вариантами являются — переопределение Equals EnemisEntity или изменение словаря Dictionary<string, int> .

Ответ №2:

Если у вас есть Dictionary , не используйте FirstOrDefault . Это будет выполнять линейный поиск до тех пор, пока он не удовлетворит Predicate отрицанию преимуществ Dictionary постоянного времени поиска. Вам нужно использовать TryGetValue on Dictionary или одну из эквивалентных функций поиска.

Чтобы использовать TryGetValue и использовать весь ваш класс в качестве ключа, вам придется переопределить Equals и GetHashCode заставить это работать

 public class EnemisEntity
{
    public string enemyType { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is EnemisEntity entity)) return false;

        return ReferenceEquals(this, obj) || string.Equals(enemyType, entity.enemyType);
    }

       
    public override int GetHashCode()
    {
        return HashCode.Combine(enemyType);
    }
}
  

теперь вы можете сделать это

 var x = new Dictionary<EnemisEntity, int>()
        {

            {new EnemisEntity{enemyType="banzai_Bill"},200 },
            {new EnemisEntity{enemyType="beach_koopa" },400 },
            {new EnemisEntity{enemyType="big_boo"},800 },
            {new EnemisEntity{enemyType="blargg"},1600 },

        };

        if (x.TryGetValue(new EnemisEntity { enemyType = "big_boo" }, out var value))
        {
            //do something with your int value
        }
  

Однако, похоже, вас интересует только сопоставление enemyType с an int , поэтому я бы изменил свой Dictionary на использование string в качестве ключа, а не EnemisEntity потому, что это упрощает все

Комментарии:

1. Создание нового EnemisEntity экземпляра каждый раз, когда вам нужно выполнить поиск в словаре, кажется неправильным. Это увеличивает нагрузку на сборщик мусора. Однако я не голосую против, потому что в некоторых случаях это может быть допустимым вариантом.

2. Я согласен, именно поэтому я предложил string в качестве ключа