Вызов определенного базового метода с несколькими перегрузками и параметрами по умолчанию - PullRequest
3 голосов
/ 22 апреля 2019

Я строю поверх исходного кода игры и пытаюсь вызвать базовую виртуальную функцию с перегруженными методами и параметрами по умолчанию. Я не могу изменить классы, от которых я наследую, и мне нужно вызвать функцию в моем собственном определении класса виртуального метода. Я попытаюсь объяснить более подробно с кодом.

Сначала у нас есть базовый класс A, который определяет виртуальную функцию с именем Foo, которая принимает один аргумент.

class A
{
   public virtual string Foo(int a)
   {
      return "Class A Function 1 par";
   }
}

Затем класс B, который переопределяет Foo и определяет новую перегруженную виртуальную функцию для Foo с двумя новыми параметрами по умолчанию.

class B : A
{
   public virtual string Foo(int a, int b = 0, int c = 0)
   {
      return "Class B Function 3 par";
   }

   public override string Foo(int a)
   {
      return "Class B Function 1 par";
   }
}

Тогда класс, из которого мне нужно получить, C. Он просто переопределяет один параметр Foo.

class C : B
{
   public override string Foo(int a)
   {
      return "Class C Function 1 par";
   }
}

Наконец, мой класс D, который также переопределяет один параметр Foo, но должен также иметь возможность вызывать базовый метод Foo.

class D : C
{
   public override string Foo(int a)
   {
      return base.Foo(0);
   }
}

Это приводит к вызову трех параметров Foo, определенных в B (возвращая как «Функция класса B 3 par»), но я хочу вызвать Foo, определенный в C (возвратил бы «Функция класса C 1 par»). Я думаю, что такая перегрузка виртуальных функций с параметрами по умолчанию вызовет неоднозначную ошибку компилятора, но она компилируется нормально.

Есть ли способ обойти это, и если нет, то почему он позволяет структуре классов блокировать мне доступ к базовому методу?

1 Ответ

3 голосов
/ 23 апреля 2019

Это неудачное взаимодействие между необязательными параметрами и остальным языком, и хорошая причина, по которой вам не следует перегружать методы, использующие необязательные параметры (или добавлять перегрузки в методы, которые этого не делают).Автор B сделал что-то действительно плохое!

Вызов не является двусмысленным, потому что правила поиска метода не меняются для base, только правила, для которых метод в конечном итоге вызываетсяпосле разрешения перегрузки - по сути, перегрузки определяются так, как если бы вызов прочитал ((C) this).Foo(0).Для этого вызова B.Foo(int, int, int) считается единственным кандидатом, потому что это ближайший не override метод при переходе по цепочке наследования - он выбирается еще до того, как мы даже рассмотрим A.Foo(int).Если бы A представил метод, не было бы проблемы, так как в этом случае перегрузка с одним параметром считалась бы лучшим методом.

Если бы необязательные параметры были частью C # с самого начала, скореечем относительно позднее добавление к стороне (с немного странной реализацией, где значения раскрываются на сайте вызова), это могло бы быть рассмотрено и как-то смягчено.Так как это наиболее очевидный способ исправить это, было бы на самом деле изменить правила для поиска base, поэтому он предпочитает сопоставлять методы, которые точно соответствуют сигнатуре метода, в котором он встречается, но это только усложнит и без того сложные правила дляРазрешение перегрузки еще больше, и оно, безусловно, может нарушить существующий код, поэтому шансы на что-то подобное случается невелики.

Если вы не можете изменить A, B и C, все еще естьспособ написать D, чтобы получить желаемое поведение, используя (если это слово) еще одну довольно неясную особенность C #, которая даже старше: группы методов!

class D : C
{
   public override string Foo(int a) 
   {
      Func<int, string> foo = base.Foo;
      return foo(a);
   }
}    

Это однозначно вызывает C.Foo(int), потому чтопреобразования делегатов в группах методов не учитывают необязательные параметры, и поэтому B.Foo(int, int, int) не является допустимым кандидатом, что вынуждает нас пойти дальше по цепочке и найти A.Foo(int).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...