Как использовать оператор switch для сравнения ссылок

#c#

Вопрос:

Я пытаюсь сопоставить ссылки на поля в своей структуре, но я не уверен, как я это делаю в качестве настройки случая, а не в случае, если заявления.

Это общая идея, которую я сделал с утверждениями if:

 public struct Test
{
   // MyObject is a class
   public MyObject A;
   public MyObject B;
   public MyObject C;

   public bool Distance(MyObject obj, out float distance){
        distance = float.PositiveInfinity;
        if(A == obj){
         distance = DistanceFrom(A);
         return true;
        }
        if(B == obj){
         distance = DistanceFrom(B);
         return true;
        }
        if(C == obj){
         distance = DistanceFrom(C); 
         return true;
        }
        //object does not relate to this struct so return false
        return false;
   }
}
 

В моей фактической структуре более 3 (всего 24), но мне интересно, как я мог бы провести это сравнение с помощью оператора case вместо этого, поскольку это было бы намного чище, чем множество операторов if. Кроме того, я не хочу использовать список из моих 24 ссылок и, следовательно, простой цикл for для его прохождения, так как в конечном итоге мои структуры будут распределены в кучу.

Можно ли выполнить переключение, сравнивая ссылки? Я знаю, как сравнивать по типу объекта, но не в том случае, если они ссылаются на один и тот же объект. Или заявления «если» — это мой единственный вариант здесь?

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

1. Здесь это похоже на проблему дизайна. Это ваш настоящий код?

2. Похоже, вы могли бы сделать сингл if , как в if(A == obj || B == obj || C == obj) .

3. Это не мой реальный код, так как мой реальный код составляет около 300 строк, и без контекста еще сложнее расшифровать то, что я собираюсь сделать, он делает кучу вещей, поэтому я привел упрощенный пример. Но одна вещь, которая у меня есть, — это множество операторов if, проверяющих, является ли объект одним из объектов, принадлежащих структурам. Что я думал, что изложение дела облегчит написание и также будет более оптимизировано.

4. Решение с использованием коллекций, вероятно, лучше.

5. Вся логика «кучи стека» и «нежелания использовать коллекцию» , возможно, ошибочна.

Ответ №1:

Хотя я согласен с комментаторами в том, что у вас могут возникнуть проблемы с дизайном, вы можете использовать when фильтр с switch .

 public bool Distance(object obj, out float distance)
{
    switch (obj)
    {
        case var _ when ReferenceEquals(obj, A):
            distance = DistanceFrom(A);
            return true;
        case var _ when ReferenceEquals(obj, B):
            distance = DistanceFrom(B);
            return true;
        case var _ when ReferenceEquals(obj, C):
            distance = DistanceFrom(C);
            return true;
        default:
            distance = float.PositiveInfinity;
            return false;
    }
}
 

Я знаю, что это выглядит немного странно, но var _ это отбрасывание и говорит, что вас не волнует значение obj (по крайней мере, само по case себе, но вы все равно можете использовать obj в when .

Вы заявили, что хотите сравнить ссылки. Вот что ReferenceEquals делает. Если вы этого не хотите, вы можете использовать == или то, что вы считаете равным.

Ответ №2:

Я бы посоветовал избегать switch и просто кодировать такие вещи напрямую.

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

 public bool Distance(object obj, out float distance)
{
    MyObject[] variables = new [] { A, B, C };
    MyObject match = variables.Where(x => ReferenceEquals(x, obj)).FirstOrDefault();
    bool result = match != null;
    distance = result ? DistanceFrom(match) : float.PositiveInfinity;
    return resu<
}
 

Или, возможно, немного более гибко:

 public float? Distance(object obj)
{
    MyObject[] variables = new [] { A, B, C };
    MyObject match = variables.Where(x => ReferenceEquals(x, obj)).FirstOrDefault();
    return match != null ? (float?)DistanceFrom(match) : null;
}
 

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

1. вы используете Array , и операция говорит, что производительность низкая…

2. Что означает «низкая производительность»? И как это связано с использованием массива?

3. пожалуйста, ознакомьтесь с комментариями под вопросом.

4. @LeiYang — Но нет никаких доказательств, что это проблема. Также можно переместить массив в поле и, таким образом, достичь того же уровня производительности, что и отдельные поля. Это спорный вопрос.

Ответ №3:

Я думаю, вам нужно прочитать официальные документы, это пример использования случая переключения с when предложением:

 public struct Test
{
   // MyObject is a class
   public MyObject A;
   public MyObject B;
   public MyObject C;

   public bool Distance(MyObject obj, out float distance){
        distance = float.PositiveInfinity;
        switch (obj){
            case MyObject o when  Object.ReferenceEquals(o,A):
              distance = DistanceFrom(A);
              return true;
            case MyObject o when  Object.ReferenceEquals(o,B):
              distance = DistanceFrom(B);
              return true;
            case MyObject o when  Object.ReferenceEquals(o,C):
              distance = DistanceFrom(C);
              return true;
            default:
              return false;
        }
        
   }
 

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

1. Как это отвечает на вопрос?

2. Я ошибаюсь в этом примере. Но находится в тех же документах.