Подтвердить что ты не робот

Действие параметра <T1, T2, T3>, в котором T3 может быть необязательным

У меня есть следующий код:

public static MyMethod()  
{ 
   ...Do something  
   ProtectedMethod(param1, param2);  
   ...Do something  
}  

protected static void ProtectedMethod(IEnumerable<string> param1, string param2, int param3 = 1)  
{  
   ... Do something  
}

Обратите внимание на необязательный параметр param3.

Теперь по целому ряду причин мне нужно извлечь код метода MyMethod в его собственный класс, но я не могу извлечь ProtectedMethod с ним из-за всех классов, которые наследуются от этого, и мне нужно, чтобы изменения были небольшими и изолированы. Поэтому я решил, что у меня может быть делегат Action < > в новом классе с той же сигнатурой, что и ProtectedMethod.

Проблема заключается в том, что если я объявляю делегат следующим образом:

protected readonly Action<IEnumerable<string>, string, int> m_ProtectedMethod;

Извлеченный код не нравится, потому что он говорит, что метод вызывается только с двумя параметрами.

И если я объявлю делегат следующим образом:

protected readonly Action<IEnumerable<string>, string> m_ProtectedMethod;

Когда я отправляю его как параметр в новый класс, ему это не нравится, потому что метод определяется как имеющий три параметра, а не два.

Пока единственный способ решить эту проблему - создать перегруженную версию ProtectedMethod для устранения необязательного параметра.

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

4b9b3361

Ответ 1

Необязательные параметры - это атрибут метода или параметра делегирования. Когда вы вызываете подпись (метод или делегат), у которой есть известный необязательный параметр во время компиляции, компилятор будет вставлять необязательное значение параметра в callsite.

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

Вместо этого вам нужно объявить пользовательский тип делегата с необязательным параметром:

public delegate void MyDelegate(IEnumerable<string> param1, string param2, int param3 = 1);

При вызове этого делегата вы сможете опустить третий параметр, независимо от объявления содержащегося в нем метода (ов).

Ответ 2

Это будет зависеть от того, как m_ProtectedMethod будет потребляться, но я нашел компромисс в своей ситуации, где я использую одну перегрузку больше, чем другую.

Просто определите более простой (имеющий менее общие параметры) Action < > variable, который вызывает более сложный метод Action Variable. Это может быть достигнуто либо в (i) локальном объеме использования; или (ii) область объекта при присвоении свойства действия или конструкции объекта.

Поскольку нет такой вещи, как перегрузка переменных/свойств, вам нужны два разных имени для двух связанных переменных Action.

EG i: Локальная область (возможно, не самая подходящая для вашего сценария)

public MyMethod(Action<IEnumerable<string>, string, int> m_ProtectedMethod2)  
{ 
   Action<IEnumerable<string>, string> m_ProtectedMethod = (p1,p2) => {
      m_ProtectedMethod2(p1,p2,1); //The value 1 is the default 3rd parameter
   }

   ...Do something  
   m_ProtectedMethod(param1, param2);  
   ...Do something  
   ...If something  
      m_ProtectedMethod2(param1, param2, param3); //Calling the more complex form directly
   ...Do something  
}  

EG ii: Область объекта

private Action<IEnumerable<string>, string, int> m_ProtectedMethod2 = null;
private Action<IEnumerable<string>, string> m_ProtectedMethod = null;
protected Action<IEnumerable<string>, string, int> ProtectedMethod
{
   get { return m_ProtectedMethod2; }
   set {
      m_ProtectedMethod2 = value;
      m_ProtectedMethod = (p1,p2) => {
         m_ProtectedMethod2(p1,p2,1); //The value 1 is the default 3rd parameter
      }
   }
}

public MyMethod()
{
   ...Do something  
   m_ProtectedMethod(param1, param2);  
   ...Do something  
   ...If something  
      m_ProtectedMethod2(param1, param2, param3); //Calling the more complex form directly
   ...Do something  
}

Обратите внимание, что в обоих случаях я настроил значение по умолчанию как более неловко названную переменную, имеющую 2 суффикса, так что при потреблении более простая перегрузка имеет более основное имя переменной.