Индекс использует H3 для определения возвращаемого столбца. Вот почему Row1 работает. Он находит столбец 6 (между B1: G1) и возвращает результат. Это только случайность, что это правильный ответ. Если бы вы подставили 5 в ячейку H2, он бы также возвратил столбец 5. В других показанных примерах функция max возвращает индекс столбца, который находится за пределами того, что находится в массиве (B1: G1 имеет длину 6 столбцов).
Чтобы исправить, соедините Index с функцией Match. Функция Match выполнит поиск в массиве (B2: G2; B3: G3 и т. Д.) И вернет номер столбца соответствующего столбца, а затем передаст его в функцию Index, чтобы получить правильный результат.
Ваша окончательная формула будет выглядеть следующим образом: = INDEX ($ B $ 1: $ G $ 1, MATCH (H2, B2: G2, 0))
Существует несколько моментов, которые я упомянул бы:
Метроном. OnTick, кажется, не называют правильно. Семантически, "OnTick" говорит мне, что это назовут, когда это "Отсчитает" s, но это не действительно, что происходит. Я звонил бы, это "Идет" вместо этого.
Обычно принятая модель, однако должен был бы сделать следующее. OnTick
виртуальный метод, который генерирует событие. Таким образом, можно переопределить поведение по умолчанию в наследованных классах легко и назвать основу, чтобы сгенерировать событие.
class Metronome
{
public event EventHandler Tick;
protected virtual void OnTick(EventArgs e)
{
//Raise the Tick event (see below for an explanation of this)
var tickEvent = Tick;
if(tickEvent != null)
tickEvent(this, e);
}
public void Go()
{
while(true)
{
Thread.Sleep(2000);
OnTick(EventArgs.Empty); //Raises the Tick event
}
}
}
Кроме того, я знаю, что это - простой пример, но если не будет никаких присоединенных слушателей, то Ваш код бросит на Tick(this, EventArgs.Empty)
. Необходимо, по крайней мере, включать пустую защиту для проверки на слушателей:
if(Tick != null)
Tick(this, EventArgs.Empty);
Однако это все еще уязвимо в многопоточной среде, если слушатель не зарегистрирован между защитой и вызовом. Лучшее должно было бы получить текущих слушателей сначала и назвать их:
var tickEvent = Tick;
if(tickEvent != null)
tickEvent(this, EventArgs.Empty);
Я знаю, что это - старый ответ, но так как он все еще собирает upvotes, вот способ C# 6 сделать вещи. Целое "защитное" понятие может быть заменено условным вызовом метода, и компилятор действительно делает Right Thing(TM) в отношении получения слушателей:
Tick?.Invoke(this, EventArgs.Empty);
Microsoft на самом деле записала обширный набор рекомендаций по именованию и поместила его в библиотеку MSDN. Можно найти статьи здесь: Инструкции для Имен
Кроме общих инструкций по капитализации, вот то, что это имеет для 'Событий' на названиях страницы участников Типа:
Действительно назовите события с глаголом или глагольной группой.
Действительно дайте именам события понятие прежде и после, с помощью настоящего и прошлого времени. Например, близкое событие, которое генерируется перед окном, закрывается, был бы назван, Закрывшись и тот, который повышен после того, как окно закрывается, был бы назван Закрытым.
Не используйте Прежде или После префиксов или суффиксов для указания пред и события сообщения.
Действительно назовите обработчики событий (делегаты используемый в качестве типов событий) с суффиксом EventHandler.
Действительно используйте два параметра, названные отправителем и e в подписях обработчика событий.
Параметр отправителя должен иметь текстовый объект, и e параметр должен быть экземпляром или наследоваться EventArgs.
Действительно назовите классы аргумента события с суффиксом EventArgs.
Точка, которую я нашел после использования событий в .NET много лет, является повторяющейся потребностью проверить событие на пустой обработчик на каждом вызове. Я должен все же видеть часть живого кода, который делает что-либо, но не называет событие, если это является пустым.
То, что я начал делать, должно поместить фиктивный обработчик на каждое событие, которое я создаю для сохранения потребности сделать пустую проверку.
public class Metronome
{
public event EventHandler Tick =+ (s,e) => {};
protected virtual void OnTick(EventArgs e)
{
Tick(this, e); // now it's safe to call without the null check.
}
}
Хорошие взгляды, кроме факта это OnTick
не следует типичной модели вызова события. Как правило, On[EventName]
генерирует событие единственное время, как
protected virtual void OnTick(EventArgs e)
{
if(Tick != null) Tick(this, e);
}
Рассмотрите создание этого метода и переименование Ваше существующее"OnTick
"метод к"StartTick
", и вместо вызова Tick
непосредственно от StartTick
, звонить OnTick(EventArgs.Empty)
от StartTick
метод.
Я бы сказал, что лучший справочник по событиям в целом, включая соглашения об именах, находится здесь .
Это соглашение, которое я принял, кратко:
Интересно, как Microsoft, похоже, нарушает свои собственные соглашения об именах с именами обработчиков событий, созданных Visual Studio.
См .: Рекомендации по именованию событий (.NET Framework 1.1)