В вашем примере, вероятно, самыми большими издержками будет создание списка, но это может быть частью демонстрации.
Начиная с массива, следующее, вероятно, будет быстрее:
int x = Array.IndexOf<string>(test_arr, "key3");
bool testCondition = x >= 0;
Но если у вас есть возможность, было бы эффективнее использовать HashSet<string>
для хранения их в первую очередь. HashSet может проверить наличие элемента в O (1).
Что касается других ваших вопросов, они уже задавались на SO, используйте опцию поиска, например, с "C # books"