Универсальный код вызова метода

#c# #generics #delegates

#c# #универсальные методы #делегаты

Вопрос:

У меня есть интерфейс с кучей методов с разными сигнатурами (контекст здесь — интерфейс обратного вызова WCF). На моем сервере есть список клиентов. В ответ на события я хочу вызывать метод интерфейса на каждом клиенте. Вокруг этого вызова есть куча кода котельной панели (проверьте, работает ли клиент, должен ли этот клиент быть включен в список для обратного вызова, попробуйте перехватить, удалите клиент, если операция завершится неудачей и т.д.). Каков наилучший способ извлечь этот код базовой панели в общий CallBackClients (SomeKindOfGenericDeligate method_to_call), где method_to_call является одним из методов интерфейса.

 ICallback {
    void Fish(string my_string);
    void SuperFish(int my_int, double my_double);
    ... etc ...
}

CallBackClients( -- ?? generic delegate ?? -- ) {
    foreach (IClientCallback client in client_list) {
        // The boiler plate code:
        if (((ICommunicationObject)client.callback).State == CommunicationState.Opened) {
            try {
               Do method call based on delagate / lamda code passed in - how ??
            }
            catch (Exception e) {
                Remove_client(client, method.ToString(), e);
            }
        }
        else
            Remove_client(client, method.ToString());
        }
    }
}
  

Псевдокод для вызывающего:

 void EventHandler_A() {
    // Call Fish method on all clients:
    CallBackClients(Fish("hello"));
}

void EventHandler_B() {
    // Call SuperFish method on all clients:
    CallBackClients(SuperFish(10, 5.3);
}
  

Ответ №1:

Вы можете инкапсулировать метод для последующего вызова в любой заданный IClientCallBack в Action<IClientCallBack> :

 CallBackClients(Action<IClientCallBack> actionOnDelegates) {
    foreach (IClientCallback client in client_list) {
        // The boiler plate code:
        if (((ICommunicationObject)client.callback).State == CommunicationState.Opened) {
            try {
               actionOnDelegates(client);
            }
            catch (Exception e) {
                Remove_client(client, method.ToString(), e);
            }
        }
        else
            Remove_client(client, method.ToString());
        }
    }
}
  

затем это будет вызываться следующим образом; они создают анонимный метод для вызова метода на указанном client :

 void EventHandler_A() {
    // Call Fish method on all clients:
    CallBackClients(client => client.Fish("hello"));
}

void EventHandler_B() {
    // Call SuperFish method on all clients:
    CallBackClients(client => client.SuperFish(10, 5.3);
}
  

Комментарии:

1. Это не сработало бы, если бы методы обратного вызова что-то вернули. Но, вероятно, здесь проблема не в этом.

2. В таком случае CallBackClients метод может быть сделан универсальным в T , а делегат может быть изменен на Func<IClientCallback, T> с передачей возвращаемого значения соответствующим образом.

3. Все обратные вызовы являются недействительными / односторонними — так что все в порядке.

4. @thecoop Отличный ответ — спасибо. Я знал, что решение существует, но я не мог полностью собрать его воедино.