Глядя на это, проблема заключается в InterfaceInterceptorClassGenerator в Unity InterceptionExtension, который обходит методы со специальными именами и не определяет методы добавления и удаления, необходимые для событий.
Возможные решения, которые я вижу, это 1) Отредактируйте исходный код Unity и напишите код, чтобы определить код IL события.(См. Ниже) 2) Измените все события в интерфейсах, которые вы хотите перехватить, на явные методы делегирования Add и Remove (которые реализуются реальным событием).Привязка WPF к INotifyPropertyChanged делает это непрактичным для Prism.3) Удалите Unity и используйте лучший контейнер IoC.
Нашли ли вы лучшее решение проблемы?
Редактировать : я застрял с Unity 1.2 на данный моментпоэтому я в конечном итоге исправил его и мог бы также опубликовать код, который также устраняет проблему производных интерфейсов.
Вам нужно будет изменить класс InterfaceInterceptorClassGenerator в Unity.Extensions.Interception, начиная с добавленияto CreateProxyType
public Type CreateProxyType()
{
int memberCount = 0;
foreach (MethodInfo method in MethodsToIntercept())
{
OverrideMethod(method, memberCount++);
}
foreach (PropertyInfo property in PropertiesToIntercept())
{
OverrideProperty(property, memberCount++);
}
// Add this
foreach (EventInfo evt in EventsToIntercept())
{
AddEvent(evt);
}
// -- SNIP --
}
Измените вещи, чтобы получить методы «базовых» интерфейсов.
private IEnumerable<MethodInfo> MethodsToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetMethods())
.Union(typeToIntercept.GetMethods())
.Where(m => !m.IsSpecialName);
}
private IEnumerable<PropertyInfo> PropertiesToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetProperties())
.Union(typeToIntercept.GetProperties());
}
private IEnumerable<EventInfo> EventsToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetEvents())
.Union(typeToIntercept.GetEvents());
}
Затем добавьте метод, который создает методы события.Это началось с использования кода из Реализация интерфейса для динамического типа с событиями , но на самом деле перенаправляет добавление / удаление в базовый объект:
private void AddEvent(EventInfo interfaceEvent)
{
MethodAttributes eventMethodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName;
MethodImplAttributes eventMethodImpAtr = MethodImplAttributes.Managed | MethodImplAttributes.Synchronized;
string qualifiedEventName = string.Format("{0}.{1}", typeToIntercept.Name, interfaceEvent.Name);
string addMethodName = string.Format("add_{0}", interfaceEvent.Name);
string remMethodName = string.Format("remove_{0}", interfaceEvent.Name);
EventBuilder eBuilder = typeBuilder.DefineEvent(qualifiedEventName, EventAttributes.None, interfaceEvent.EventHandlerType);
// ADD method
MethodBuilder addMethodBuilder = typeBuilder.DefineMethod(addMethodName, eventMethodAttr, null, new[] { interfaceEvent.EventHandlerType });
addMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// Code generation
ILGenerator ilgen = addMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, targetField);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, interfaceEvent.GetAddMethod());
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);
// REMOVE method
MethodBuilder removeMethodBuilder = typeBuilder.DefineMethod(remMethodName, eventMethodAttr, null, new[] { interfaceEvent.EventHandlerType });
removeMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// Code generation
ilgen = removeMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, targetField);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, interfaceEvent.GetRemoveMethod());
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);
// Finally, setting the AddOn and RemoveOn methods for our event
eBuilder.SetAddOnMethod(addMethodBuilder);
eBuilder.SetRemoveOnMethod(removeMethodBuilder);
}
Возможно, вам также нужно что-то сделатьаналогично для индексаторов, если они есть в интерфейсе, но легко изменить интерфейс для получения / установки методов.