Просто для уточнения, у меня это работает с использованием динамического и 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")]
обработчик вызывает функцию следующие выполнения на одноэлементных класса для «выполнения» функций, которые зарегистрированы (добавлены в коллекцию).
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 во время вызова .
Я понимаю, почему я не могу сделать это с помощью моей текущей реализации. Я просто пытаюсь найти способ обернуть всю эту функциональность, не используя динамический. И надеялся, что кто-то может предоставить некоторые советы, которые могут быть полезны. обертывая это другими вызовами не-генерических классов или что-то в этом роде, это было бы хорошо, если это единственное решение.
Что вы будете делать с результатами, если у вас есть? Похоже, вам нужен соответствующий интерфейс 'IHandler' для обработки результатов. Затем вы можете просто скомпоновать методы 'Execute' и' Handle' как 'Action'. –
Lee
Я добавил функцию обертки, которую я могу использовать для агрегирования результатов вызовов, надеюсь, что ответит на ваш вопрос. Или, может быть, я не понимаю ваш ответ? – Brandon
Думаю, я понимаю, о чем вы говорите, что имеет смысл. Тем не менее, учитывая, что мне нужно вернуть некоторые из этих значений, я думаю, столкнулся бы с той же проблемой знания типа T в вызывающем. Я знаю, что это неотъемлемая проблема с этим. Я предполагаю, что это просто природа зверя, и единственное, что я могу сделать, это добавить некоторую проверку/кастинг в вызывающем, чтобы соответствующим образом разобраться с результатами. Охлаждающая (но опасная) вещь о динамике - это то, что мне не нужно ссылаться на результат. Но когда-то это в динамике своего рода в философски «серой» области. – Brandon