Прием создать отдельный поток, ответственный за показ экрана-заставки.
при выполнении Вас приложение .net создает основной поток и загружает определенную (основную) форму. Для сокрытия тяжелой работы, можно скрыть основную форму, пока загрузка не сделана.
Предположение, что Form1 - является Вашей основной формой и SplashForm, является верхним уровнем, безграничной хорошей формой всплеска:
private void Form1_Load(object sender, EventArgs e)
{
Hide();
bool done = false;
ThreadPool.QueueUserWorkItem((x) =>
{
using (var splashForm = new SplashForm())
{
splashForm.Show();
while (!done)
Application.DoEvents();
splashForm.Close();
}
});
Thread.Sleep(3000); // Emulate hardwork
done = true;
Show();
}
Простой случай выглядит так: у вас есть массив операций (функций) в соответствии с вашей бизнес-логикой. У вас есть функция хеширования, которая сводит проблему ввода к одной из функций бизнес-логики. Чистый код будет иметь массив указателей на функции, и ваша программа будет выводить индекс этого массива из входных данных и вызывать его.
Вот пример кода:
typedef void (*fn)(void) FNTYPE;
FNTYPE fn_arr[5];
fn_arr[0] = fun1; // fun1 is previously defined
fn_arr[1] = fun2;
...
void callMyFun(string inp) {
int idx = decideWhichFun(inp); // returns an int between 0 and 4
fn_arr[idx]();
}
Но, конечно, обратные вызовы - наиболее распространенное использование . Пример кода ниже:
void doLengthyOperation(string inp, void (*callback)(string status)) {
// do the lengthy task
callback("finished");
}
void fnAfterLengthyTask(string status) {
cout << status << endl;
}
int main() {
doLengthyOperation(someinput, fnAfterLengthyTask);
}
Один довольно распространенный вариант использования - это функция обратного вызова. Например, если вы загружаете что-то из БД, вы можете реализовать свою функцию загрузки, чтобы она сообщала о ходе выполнения функции обратного вызова. Это можно сделать с помощью указателей функций.
Обратные вызовы. Я выполняю асинхронный вызов фрагмента кода и хочу, чтобы он сообщал мне, когда он завершится, я могу отправить ему указатель функции для вызова, как только он будет выполнен.
Вы используете указатель на функцию, когда вам нужно предоставить метод обратного вызова. Один из классических примеров - регистрация обработчиков сигналов - какая функция будет вызываться, когда ваша программа получит сигнал SIGTERM (Ctrl-C)
Вот еще один пример:
// The four arithmetic operations ... one of these functions is selected
// at runtime with a switch or a function pointer
float Plus (float a, float b) { return a+b; }
float Minus (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide (float a, float b) { return a/b; }
// Solution with a switch-statement - <opCode> specifies which operation to execute
void Switch(float a, float b, char opCode)
{
float result;
// execute operation
switch(opCode)
{
case '+' : result = Plus (a, b); break;
case '-' : result = Minus (a, b); break;
case '*' : result = Multiply (a, b); break;
case '/' : result = Divide (a, b); break;
}
cout << "Switch: 2+5=" << result << endl; // display result
}
// Solution with a function pointer - <pt2Func> is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// "specifies" which operation shall be executed.
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
float result = pt2Func(a, b); // call using function pointer
cout << "Switch replaced by function pointer: 2-5="; // display result
cout << result << endl;
}
Вы можете узнать больше об указателях функций здесь http: //www.newty.de/fpt/index.html
Если вы более знакомы с объектно-ориентированными языками, вы можете думать об этом как о способе C реализовать шаблон разработки стратегии .
]Я удивлен, что никто не упомянул "конечные автоматы". Указатели на функции - очень распространенный способ реализации конечных автоматов для таких задач, как синтаксический анализ. См., Например: ссылка .
Давайте сделаем map
-подобную функцию для C.
void apply(int *arr, size_t len, int (*func)(int))
{
for(size_t i = 0; i < len; i++)
arr[i] = func(arr[i]);
}
Таким образом, мы можем преобразовать функцию, которая работает с целыми числами, для работы с массивами целых чисел. Мы также могли бы сделать аналогичную версию:
void apply_enumerated(int *arr, size_t len, int (*func)(size_t, int))
{
for(size_t i = 0; i < len; i++)
arr[i] = func(i, arr[i]);
}
Это делает то же самое, но позволяет нашей функции знать, на каком элементе она находится. Мы могли бы использовать это, например:
int cube(int i) { return i * i * i }
void print_array(int *array, size_t len, char *sep)
{
if(sep == NULL) sep = ", ";
printf("%d", *array);
for(size_t i = 1; i < len; i++) printf("%s%d", sep, array[i])
}
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
int main(void)
{
int array[5] = { 1, 2, 3, 4, 5 };
print_array(array, ARRAY_SIZE(array), NULL);
apply(array, ARRAY_SIZE(array), cube);
print_array(array, ARRAY_SIZE(array), NULL);
return 0;
}
Этот код напечатает:
1, 2, 3, 4, 5
1, 8, 27, 64, 125
Для нашего примера перечисления:
int mult(size_t i, int j) { return i * j }
// print_array and ARRAY_SIZE as before
int main(void)
{
int array[5] = { 1, 2, 3, 4, 5 };
print_array(array, ARRAY_SIZE(array), NULL);
apply_enumerated(array, ARRAY_SIZE(array), mult);
print_array(array, ARRAY_SIZE(array), NULL);
return 0;
}
Это напечатает:
1, 2, 3, 4, 5
0, 2, 6, 12, 20
Как более реальный пример, строковая библиотека может иметь функцию, которая применяет функция, которая работает с одиночными символами для всех символов в строке. Примером таких функций являются функции стандартной библиотеки toupper ()
и tolower ()
в ctype.
Очень хорошее и понятное руководство: http://www.newty.de/fpt/index.html
Надеюсь, это поможет.
Другое использование указателей - это итерация списков или массивов.
Для кода проверьте ответ qrdl на учебные пособия по конечным автоматам .
Я использовал вариант его метода для реализации меню для ЖК-дисплея, который у меня есть на плате. Очень-очень полезно, делает код намного чище и легче читается. Использование указателей функций позволяет очень легко расширить количество, имена и порядок меню и скрыть все эти детали от функции вызова более высокого уровня, которая просто видит «эй, я пишу на ЖК-дисплей здесь».