Я пишу программу на C# (3.5 на данный момент, но, возможно, ее можно адаптировать к другим версиям по мере необходимости), которая использует простую архитектуру плагина для управления вводом и выводом. Каждый плагин представляет собой DLL, которая загружается, когда пользователь выбирает плагины для использования.C# Generic Method vs Casting
Поскольку фактический класс плагина неизвестен до времени выполнения, я использую отражение в классе-оболочке для вызова методов и доступа к свойствам плагинов.
До сих пор я использую следующие для вызова методов плагина:
public object Method(string methodName, params object[] arguments) {
// Assumed variables/methods/exceptions:
// Dictionary<string, MethodInfo> Methods: a cache of MethodInfo's
// of previously called methods.
// NoSuchMethodException: thrown if an unknown/unreachable method is
// requested. The message member contains the invalid method name
// void LoadMethod(string methodName, params object[] arguments): responsible
// for retrieving the MethodInfo's, or throw a NoSuchMethodException
// object Plugin: an instance of the dynamically loaded class.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return Methods[methodName].Invoke(Plugin, arguments);
}
Который используется как:
string[] headers = (string[]) Plugin.Method("GetHeaders", dbName, tableName);
Это прекрасно работает, до тех пор, вызывающему правильно возвращает возвращаемое значение в ожидаемый тип . Плагины должны реализовывать определенные интерфейсы, поэтому вызывающий должен знать этот тип.
После выполнения некоторых дальнейшей работы с отражением, однако, следующий альтернативная форма пришла мне в голову:
public T Method<T>(string methodName, params object[] arguments) {
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (Methods[methodName].ReturnType != typeof(T)) {
// Could also move this into LoadMethod to keep all the throwing in one place
throw new NoSuchMethodException(methodName);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return (T) Methods[methodName].Invoke(Plugin, arguments);
}
Это один используется как:
string[] headers = Plugin.Method<string[]>("GetHeaders", dbName, tableName);
Эта версия существенно сдвигает литьем в методе метод. Вызывающему, очевидно, все еще нужно знать ожидаемый тип возвращаемого значения, но это всегда будет так. Это не работает для недействительных методов, но может включать в себя версию метода для этого:
public void Method(string methodName, params object[] arguments) {
// Good for void methods, or when you're going to throw away the return
// value anyway.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
Methods[methodName].Invoke(Plugin, arguments);
}
Мой вопрос - это один из них внутренне лучше, чем другой (для данного значения «лучше») ? Например, это особенно заметно быстрее? Легче понять? Больше поддерживается?
Мне лично нравится внешний вид последнего, хотя я немного обеспокоен тем, что мое тестирование типа возвращаемого типа (Methods[methodName].ReturnType != typeof(T)
) может быть слишком упрощенным. Интересно, что это было изначально !(Methods[methodName].ReturnType is T)
, но это всегда казалось неудачным.
Ближайший существующий вопрос к этому, который я мог найти, был Generic method to type casting, и некоторые из ответов предполагали, что последний метод дороже первого, но там не так много деталей (вопрос о том, реализация метода, а не лучше).
Уточнение: Это ручная, очень ограниченная система плагинов, не использующая IPlugin. Меня больше интересует вопрос о том, являются ли общие методы по своей природе лучше/хуже, чем ожидание вызова в этой ситуации.
Ум в обоих направлениях, похоже, делает то же самое? Один из них использует метод, другой - снаружи? – lahsrah
Почему вы используете детали реализации из плагинов? – ChaosPandion
@sylon Я знаю, что они оба делают одно и то же - мой вопрос в том, какой (если есть) «лучше». – MDB