Функторы, когда я должен использовать их, что [закрывается] их надлежащее использование

Вы должны использовать функцию keydown для захвата символов Ctrl . Вот моя реализация Ctrl + A :

    $(document).keydown(function(e) {
        if (e.keyCode == 65 && e.ctrlKey) {
            alert('ctrl A');
        }
    });

Ctrl-R сложнее, поскольку в большинстве браузеров, то есть Обновить страницу , что означает, что javascript не запускается, страница обновляется.

Кроме того, примечание: значение keyCode отличается в функциях keydown / keyupup от функций нажатия клавиш.

РЕДАКТИРОВАТЬ: Удалена переменная ctrl, забыли о ctrlKey

13
задан Benjamin 13 July 2014 в 09:10
поделиться

4 ответа

Я думаю, вы путаете термины из разных языков. Похоже, вы используете "Functor" в смысле C ++ или Java, например см. Страницу википедии . В C ++ это объект класса, который перегружает оператор вызова функции, поэтому его можно использовать как функцию, но с состоянием.

Логически это то же самое, что и делегат, привязанный к методу экземпляра в C # (или любой язык .NET).

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

void MyMethod() { Console.WriteLine("Hi!"); }

void Foo()
{
    Action a = MyMethod;
    a();
}

Во-вторых, вы можете использовать синтаксис анонимного метода, представленный в C # 2.0:

void Foo()
{
    Action a = delegate { Console.WriteLine("Hi!"); }
    a();
}

В-третьих, вы можете использовать лямбда-синтаксис, введено в C # 3.0:

void Foo()
{
    Action a = () => Console.WriteLine("Hi!");
    a();
}

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

Преимущество лямбда-синтаксиса над анон-методами состоит в том, что он более лаконичен и делает вывод типа по параметрам.

Обновление: Преимущество анон-методов ( ключевое слово делегата ) over lambdas заключается в том, что вы можете полностью опустить параметры, если они вам не нужны:

// correct way using lambda
button.Click += (sender, eventArgs) => MessageBox.Show("Clicked!");

// compile error - wrong number of arguments
button.Click += () => MessageBox.Show("Clicked!");

// anon method, omitting arguments, works fine
button.Click += delegate { MessageBox.Show("Clicked!"); };

Я знаю только одну ситуацию, когда это стоит знать, а именно при инициализации события, чтобы вам не приходилось проверять null перед его запуском:

event EventHandler Birthday = delegate { };

Избегает много чепухи в другом месте.

Наконец, вы упоминаете, что существует четыре вида функторов. На самом деле существует бесконечное количество возможных типов делегатов, хотя у некоторых авторов могут быть свои фавориты, и, очевидно, будут некоторые общие шаблоны. Действие или Команда не принимает параметров и возвращает void , а предикат принимает экземпляр некоторого типа и возвращает истина или ложь .

В C # 3.0 вы можете создать делегат с четырьмя параметрами любых типов, которые вам нравятся. :

Func<string, int, double> f;  // takes a string and an in, returns a double

Re: Обновленный вопрос

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

Вы чаще всего видите их в середине более крупных выражений, которые работают с последовательностями (списки, вычисляемые на лету). Предположим, у меня есть список людей, и мне нужен список людей, которым ровно сорок лет:

var exactlyForty = people.Where(person => person.Age == 40);

Метод Where - это метод расширения интерфейса IEnumerable , где T в данном случае является своего рода классом Person .

Это известно в .NET как «Linq to Objects»,

23
ответ дан 1 December 2019 в 20:01
поделиться

В терминах .NET, я думаю, то, что вы описываете, является Делегатом - и он существует во всей .NET, а не только в C #.

Я не уверен, что «замыкание» будет «типом» в том же смысле, что и компаратор / предикат / преобразователь, поскольку в терминах C # замыкание - это просто деталь реализации, но может быть любой из этих трех.

В .NET делегаты используются двумя основными способами:

  • как механизм событий
  • для обеспечения программирования в функциональном стиле

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

List<int> vals = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> evenVals = vals.FindAll(i => i % 2 == 0); // predicate
List<string> valsAsStrings = vals.ConvertAll(i => i.ToString()); // transformer
// sort descending
vals.Sort((x, y) => y.CompareTo(x)); // comparer

Замыкание - это больше, когда мы переносим дополнительную область видимости из вне делегата в делегата:

int max = int.Parse(Console.ReadLine()); // perhaps 6
List<int> limited = vals.FindAll(i => i <= max);

здесь max фиксируется в делегате как закрытие.

Re "Подготовлены ли для этого классы в структуре?" - многие из них, и LINQ идет длинным путем, чтобы сделать это еще шире. LINQ предоставляет методы расширения (например) для всех IEnumerable - это означает, что коллекции без доступа на основе делегатов получают их бесплатно:

int[] data = { 1,2,3,4,5,6,7,8,9 };
var oddData = data.Where( i => i % 2 == 1 );
var descending = data.OrderBy(i => -i);
var asStrings = data.Select(i => i.ToString());

Здесь Где и OrderBy методы - это методы расширения LINQ, которые принимают делегатов.

7
ответ дан 1 December 2019 в 20:01
поделиться

Интересно с терминологией; Моя спонтанная интерпретация термина «Функтор» заключалась в том, что он относится к анонимным методам. Так что это будет мой подход.

Вот некоторые из моих типичных применений:

Сравнения (обычно для сортировки списка):

List<int> ints = new List<int>();
ints.AddRange(new int[] { 9, 5, 7, 4, 3, 5, 3 });
ints.Sort(new Comparison<int>(delegate(int x, int y)
    {
        return x.CompareTo(y);
    }));
// yes I am aware the ints.Sort() would yield the same result, but hey, it's just
// a conceptual code sample ;o)

// and the shorter .NET 3.5 version:
ints.Sort((x, y) =>
{
    return x.CompareTo(y);
});

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

Еще одно из моих довольно распространенных применений - модульное тестирование, когда тест полагается на какое-то событие, возникающее . Я обнаружил, что это важно при модульном тестировании рабочих процессов в Workflow Foundation:

WorkflowRuntime runtime = WorkflowHost.Runtime;  
WorkflowInstance instance = runtime.CreateWorkflow(typeof(CreateFile)); 
EventHandler<WorkflowEventArgs> WorkflowIdledHandler = delegate(object sender, WorkflowEventArgs e)
{
    // get the ICreateFileService instance from the runtime  
    ISomeWorkflowService service = WorkflowHost.Runtime.GetService<ISomeWorkflowService>();

    // set the desired file content  
    service.DoSomeWork(instance.InstanceId, inputData);
};  
// attach event handler
runtime.WorkflowIdled += WorkflowIdledHandler;  

instance.Start();  
// perform the test, and then detach the event handler
runtime.WorkflowIdled -= WorkflowIdledHandler; 

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

Есть и другие случаи, когда я нахожу это в своем коде, но обычно у них есть одна или две общие черты:

  • Мне не интересно ссылаться на этот фрагмент кода из любого другого места чем в этом конкретном месте .
  • Методу необходим доступ к данным, которые были бы вне области действия обычного метода
1
ответ дан 1 December 2019 в 20:01
поделиться

Я уверен, что вы имеете в виду лямбда-выражения. Это небольшие функции, которые вы можете написать очень быстро, и они имеют характерный оператор "=>". Это новая функция C # 3.0.

Этот пример будет классическим преобразователем; чтобы использовать его, нам нужен делегат для определения сигнатуры лямбда-функции.

delegate int Transformer(int i);

Теперь объявите лямбда-выражение с помощью этого делегата:

Transformer sqr = x => x * x;

Мы можем использовать его как обычную функцию:

Console.WriteLine(sqr(3)); //9

Они часто используются в запросах LINQ , например, для сортировки (Comparer), для поиска (Predicate).

В книге «C # Pocket Reference» (не считая лучшего, на мой взгляд, есть очень хорошая часть по лямбдам) (ISBN 978-0 -596-51922-3)

0
ответ дан 1 December 2019 в 20:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: