Сначала используйте выражение блока, чтобы ввести runnerParameter
в контекст.Во-вторых, сделайте параметр e
базовым типом, чтобы вам не приходилось связываться с типом делегата, а затем преобразуйте его в производный тип с помощью выражения преобразования.В-третьих (необязательно), используйте общую перегрузку Expression.Lambda
, чтобы получить желаемый тип делегата без приведения.
var eventParameter = Expression.Parameter(typeof(Event), "e");
var body = Expression.Call(runnerParameter, method, Expression.Convert(eventParameter, eventType));
var block = Expression.Block(runnerParameter, body);
var lambda = Expression.Lambda<Action<Event>>(block, eventParameter);
var compiled = lambda.Compile();
_handlers.Add(eventType, compiled);
Это будет работать до тех пор, пока вы не вызовете хандер, а затем получите NRE, потому что runnerParameter
не имеет значения.Измените его на константу, чтобы ваш блок закрывался на this
.
var runnerParameter = Expression.Constant(this, this.GetType());
Еще одно предложение: уберите критерии выбора / исключения из цикла, чтобы не смешивать опасения, и сохраняйте фактыобнаружен в анонимном объекте для последующего использования.
var methods = from m in this.GetType().GetMethods()
where m.Name == HandleMethodName
let parameters = m.GetParameters()
where parameters.Length == 1
let p = parameters[0]
let pt = p.ParameterType
where pt.IsClass
where !pt.IsAbstract
where typeof(Event).IsAssignableFrom(pt)
select new
{
MethodInfo = m,
ParameterType = pt
};
Затем, когда вы зацикливаетесь на methods
, вы только создаете делегат.
foreach (var method in methods)
{
var eventType = method.ParameterType;
var eventParameter = Expression.Parameter(typeof(Event), "e");
var body = Expression.Call(runnerParameter, method.MethodInfo, Expression.Convert(eventParameter, eventType));
var block = Expression.Block(runnerParameter, body);
var lambda = Expression.Lambda<Action<Event>>(block, eventParameter);
var compiled = lambda.Compile();
_handlers.Add(eventType, compiled);
}
EDIT: При ближайшем рассмотрении я понял, что выражение блока не нужно.Создание runnerParameter
константного выражения само по себе решает проблему, выходящую за рамки.