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

С#: Func <> вместо методов?

Это любопытные вопросы для всех вас в курсе:

Есть ли вред/недостаток использования Func вместо метода? Простой пример:

private static Func<int, int, DBContext, List<T>> Foo =
    (i1, i2, dbc) =>
        (i1 != 0) ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };

Vs

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    return i1 != 0 ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };
}
4b9b3361

Ответ 1

Я вижу уменьшенные нижние уровни:

  • Влияние производительности (метод делегирования против метода) - маленький, но он там
  • нет параметров (ухудшает читаемость при вызовах)
  • само определение менее читаемо
  • невозможна перегрузка (благодаря xanatos)

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

Ответ 2

Производительность - это не столько аргумент, сколько казалось бы первоначально, стоимость вызова делегата и метод, который отправляется через v_table (методы виртуального экземпляра), сопоставимы. В этом случае для статического метода, вероятно, существует небольшое усиление производительности для использования делегата.

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

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

С# - это язык с несколькими парадигмами, и использование каждой парадигмы имеет свое место. Функциональные парадигмы (такие как использование Funcs вместо известных методов времени компиляции) имеют свое место, как и объектно-ориентированные парадигмы. В вашем случае нет пользы от использования Func<>, вместо этого вы должны использовать традиционный метод для ясности.

Ответ 3

В первом случае (с Func) вы не пишете метод, а переменную Foo, которую вы инициализируете определенным делегатом. У вас есть один уровень косвенности, который вы можете использовать, чтобы изменить то, что указывает Foo. Чтобы упростить свой пример:

public static class Test {

    public static Func<int, int, int> Foo =
        (i1, i2) =>
            i1 + i2;

    public static int Foo2(int i1, int i2)
    {
        return i1 + i2;
    }
}

пусть тест:

int a = Test.Foo(2,3);
int b = Test.Foo2(2,3);

Console.WriteLine("{0}, {1}",a,b); // 5, 5, all seems good, they're both sums

    //... but wait... now you can do this:
Test.Foo = (x,y) => x * y; //reassigning Foo
int c = Test.Foo(2,3);
Console.WriteLine("{0}",c); // 6 

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

Ответ 4

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

если у вас есть веские причины использовать его, как вы создаете Func динамически на основе определенных условий, тогда использование Func < > оправдано..

Также взгляните на действие. вот блог, который я читаю, чтобы объяснить, когда использовать что: http://simpleprogrammer.com/2010/09/24/explaining-what-action-and-func-are/

Ответ 5

С точки зрения "учебной книги" это должно быть одно и то же, но

  • небольшое влияние на производительность, потому что lambdas/делегаты немного медленнее, чем методы. Параметры
  • имеют общие имена (например, arg1, arg2)
  • Intellisense обычно не может предоставить подсказки для документации
  • Методы, определенные как лямбда-поля, не могут вводить новые общие параметры
  • воздействие на читаемость

Ответ 6

Помимо понижения читаемости, я не думаю, что есть другой вред. Не уверен, как компилируется код, но в первой версии вы просто определяете функцию с помощью делегата. Я полагаю, вы также можете сделать следующее:

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    i1 != 0 ? return dbc.Bar(i2) : return new List<T> { /*some default values ...*/ };
}

private static Func<int, int, DBContext, List<T>> Foo2 = Foo;