Вы должны использовать функцию keydown для захвата символов Ctrl kbd>. Вот моя реализация Ctrl kbd> + A kbd>:
$(document).keydown(function(e) {
if (e.keyCode == 65 && e.ctrlKey) {
alert('ctrl A');
}
});
Ctrl-R сложнее, поскольку в большинстве браузеров, то есть Обновить страницу , что означает, что javascript не запускается, страница обновляется.
Кроме того, примечание: значение keyCode отличается в функциях keydown / keyupup от функций нажатия клавиш.
РЕДАКТИРОВАТЬ: Удалена переменная ctrl, забыли о ctrlKey
Я думаю, вы путаете термины из разных языков. Похоже, вы используете "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»,
В терминах .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, которые принимают делегатов.
Интересно с терминологией; Моя спонтанная интерпретация термина «Функтор» заключалась в том, что он относится к анонимным методам. Так что это будет мой подход.
Вот некоторые из моих типичных применений:
Сравнения (обычно для сортировки списка):
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;
В этом случае проще объявить обработчик событий как анонимные методы, поскольку он использует переменную экземпляра
, которая определена в области метода модульного тестирования. Если бы я вместо этого решил реализовать обработчик событий как отдельный метод, мне также нужно было бы выяснить, как он может получить экземпляр
, возможно, путем введения члена уровня класса, который не выглядел бы как идеальный дизайн в классе модульного тестирования.
Есть и другие случаи, когда я нахожу это в своем коде, но обычно у них есть одна или две общие черты:
Я уверен, что вы имеете в виду лямбда-выражения. Это небольшие функции, которые вы можете написать очень быстро, и они имеют характерный оператор "=>". Это новая функция 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)