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

Использование условного оператора (?:) для выбора метода в С# (3.0)?

Я рефакторинг кода.

В настоящее время существует довольно много мест с такими функциями:

string error;
if (a) {
   error = f1(a, long, parameter, list);
}
else {
   error = f2(the_same, long, parameter, list);
}

перед рефакторингом f1 и f2 (которые являются большими, но делают подобные вещи), я бы хотел реорганизовать:

string error = (a ? f1 : f2)(a, long, parameter, list);

Как и в C. (Подписи функций идентичны)

Но я получаю сообщение об ошибке:

"Ошибка 13 Тип условного выражения не может быть определен, потому что не существует неявного преобразования между" группой методов "и" группой методов "

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

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

Извините, что редактировал, но на самом деле есть возвращаемое значение, и да, к сожалению, это строка.; - (

Сейчас я соглашаюсь на это:

string error = a ? f1(a, long, parameter, list) : f2(a, long, parameter, list);

Проблема в том, что список параметров действительно очень длинный и собирается получить рефакторинг, и я предпочел бы, чтобы они сначала консолидировались и обрабатывали ошибки компилятора, когда я их изменяю.

4b9b3361

Ответ 1

Вы можете это сделать, объявив делегата, как вы указали.

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

IFoo foo = a ? new Foo1() : new Foo2();
foo.f(a, long, parameter, list);

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

Ответ 2

Для работы ? компилятору нужен явный тип для хотя бы одного из операндов. Вы можете предоставить его здесь с помощью оператора трансляции

(a ? (Action<T1,T2,T3,T4>)f1 : f2)(a, long, parameter, list);

Замените T* на фактические типы параметров делегата

Ответ 3

Вам необходимо создать экземпляр одного из методов в качестве определенного типа совместимого делегата. Там просто нет пути. Это, к сожалению, будет немного более подробным, чем вы ищете:

(a ? new Action<T1, T2, T3, T4>(f1) : f2)(a, long, parameter, list);

Вам нужно будет сделать параметры явными, будь то с помощью общей перегрузки Action (или Func), которая соответствует или объявляет ваш собственный тип делегата.

Это сводится к разрешению типа. Учитывая выражение:

condition ? tVal : fVal

Компилятор не ищет общих совместимых с назначением предков для tVal и fVal (и, даже если бы это произошло, может быть огромным множество разных типов делегатов, для которых каждый может быть действительным); если между типами tVal и fVal нет совместимости присвоений в любом направлении, компилятор делает вас явным в отношении того, что вы хотите.

Для чего вам стоит знать, что при таком подходе каждый раз при вызове этого метода будет выделен новый делегат либо f1, либо f2, тогда этот делегат будет вызываться, а затем отбрасываться. Я выношу это только потому, что вызов делегата медленнее обычного вызова метода ранней привязки (или даже виртуального). Это может не быть соображением, и компромисс может стоить того, но он все равно стоит знать.

Ответ 4

Если вы укажете тип делегата, это позволит вам делать то, что вы просите:

    (test ? (Action<int,int>)M1 : M2)(10, 15)

С объявлениями:

    void M1(int a, int b)
    {
    }

    void M2(int a, int b)
    {
    }

Протестировано с .Net 4, но должно применяться для .Net 3.5

Ответ 5

Нет, в основном, не делая его менее эффективным. Если есть возвращаемое значение, вы можете использовать:

var result = cond ? methodA(a,b,c,d) : methodB(a,b,c,d);

но об этом.

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

Ответ 6

Я думаю, что что-то вроде следующего будет работать лучше:

a? f1 (a, long, параметр, список): f2 (a, long, параметр, список);

Ответ 7

Перенесите результат тройного на Action

((Action<int, int>)(a ? f1 : f2))(int1, int2);