Просто, чтобы уточнить, у меня есть работа с использованием динамического и MakeGenericType. Но я не могу помочь, но думаю, что есть лучший способ сделать это. То, что я пытаюсь сделать, это создать "подключаемый" загрузчик, используя Unity. Я просто объясню это, когда отправлю код, чтобы вы могли понять, что я делаю.
Сначала я просто опубликую сам подключаемый модуль:
[RegisterAction("MyPlugin", typeof(bool), typeof(MyPlugin))]
public class MyPlugin: IStrategy<bool>
{
public IStrategyResult<bool> Execute(ISerializable info = null)
{
bool result;
try
{
// do stuff
result = true;
}
catch (Exception)
{
result = false;
}
return new StrategyResult<bool>
{
Value = result
};
}
}
Несколько вещей, чтобы отметить здесь. Первый - это атрибут RegisterActionAttribute:
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public StrategyAction StrategyAction { get; }
public RegisterActionAttribute(string actionName, Type targetType, Type returnType, params string[] depdencies)
{
StrategyAction = new StrategyAction
{
Name = actionName,
StrategyType = targetType,
ResponseType = returnType,
Dependencies = depdencies
};
}
}
Тогда интерфейсы:
public interface IStrategy<T>
{
IStrategyResult<T> Execute(ISerializable info = null);
}
public interface IStrategyResult<T>
{
bool IsValid { get; set; }
T Value { get; set; }
}
Все довольно прямолинейно. Цель здесь - просто прикрепить некоторые метаданные к классу при его загрузке. Загрузка происходит через единицу с помощью обертки, которая просто загружает сборки в каталоге bin с помощью шаблона поиска файлов и добавляет его в одноэлементный класс с коллекцией StrategyActions. Мне не нужно вставлять весь код единицы здесь, поскольку я знаю, что он работает, и регистрирует и разрешает сборки.
Итак, теперь к мясу вопроса. У меня есть функция на синглетоне, которая выполняет действия. Они применяются с Unity.Interception HandlerAttributes и передают такую строку (я могу опубликовать код для этого, но я не думаю, что это было важно):
[ExecuteAction("MyPlugin")]
Обработчик вызывает следующую функцию выполнения в классе singleton для "выполнения" функций, которые зарегистрированы (добавлены в коллекцию).
public dynamic Execute(string action, params object[] parameters)
{
var strategyAction = _registeredActions.FirstOrDefault(a => a.Name == action);
if (strategyAction == null)
return null;
var type = typeof (IStrategy<>);
var generic = type.MakeGenericType(strategyAction.StrategyType);
var returnType = typeof (IStrategyResult<>);
var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = UnityManager.Container.Resolve(generic, strategyAction.Name);
var method = instance.GetType().GetMethod("Execute");
return method.Invoke(instance, parameters);
}
Этот результат завершается вызовом перечислителя, который возвращает коллекцию результатов, которая сортирует для управления зависимостями и что нет (см. ниже). Эти значения ссылаются на вызывающего абонента, используя свойство Value ISTrategyResult {T} для выполнения различных действий, определенных другими бизнес-правилами.
public List<dynamic> ExecuteQueuedActions()
{
var results = new List<dynamic>();
var actions = _queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
_queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
Теперь помните, что это работает, и я получаю тип возвращаемого значения, указанный атрибутом RegisterAction плагинов. Как вы можете видеть, я захватываю тип плагина и тип возвращаемого значения. Я использую "общую" переменную, чтобы разрешить тип с единством с помощью MakeGenericType, который отлично работает. Я также создаю общий тип возвращаемого типа, основанный на типе из коллекции.
Мне здесь не нравится использовать динамику, чтобы вернуть это значение функции. Я не могу найти способ вернуть это как IStrategyResult {T}, потому что, очевидно, вызывающий объект для "dynamic Execute (..." ) не может во время выполнения использовать возвращаемый тип функции. вызов Execute с вызовом MakeGenericMethod, поскольку у меня на самом деле есть ожидаемый тип StrategyAction. Было бы здорово, если бы я мог каким-то образом выяснить, как это сделать, чтобы вернуть строго типизированный результат IStrategyResult {T} при определении типа T во время вызова.
Я понимаю, почему я не могу сделать это с моей текущей реализацией. Я просто пытаюсь найти способ обернуть все эти функции, не используя динамический. И надеялся, что кто-то может дать некоторые советы, которые могут быть полезны. Если это означает перенос этого с другими вызовами в не-общие классы или что-то в этом роде, это было бы хорошо, если это единственное решение.