(я не уверен на 100%, что понимаю, к чему вы собираетесь подключить сгенерированный обработчик событий из примера, но вот самый простой способ, которым я знаю для создания обработчика событий)
Зависит от вашей платформы и уровня доверия. Наиболее гибкий способ сделать это - использовать Emit
для генерации метода (см. здесь ).
Однако я нашел относительно простую в использовании и хорошую альтернативу для генерации выражений Linq (вот справка для пространства имен ).
Идея довольно проста:
Используйте различные производные от Expression классы, которые вы можете видеть в пространстве имен, чтобы определить, что делает ваш обратный вызов. В этом случае вы хотите сгенерировать что-то, что вызывает .RemoveEventHandler
(я предполагаю) на экземпляре ei
(в частности, вы будете использовать ConstantExpression , чтобы создать ссылку на вашу переменную ei
и к вашему параметру Callback и MethodCallExpression для создания вызова метода RemoveDataHandler
).
Как только вы создадите выражение, которое делает то, что вам нужно, вам нужно создать из него делегат (лямбда) (см. здесь )
Почти готово. Вам все еще нужно скомпилировать лямбду, которую вы делаете, вызывая .Compile
для объекта, полученного на предыдущем шаге ( см. Здесь )
Редактировать: Это пример консоли Windows для динамически генерируемого делегата, который удаляет себя. Обратите внимание, что поддержка выражений WP7 Linq более ограничена, чем .NET 4.0, и поэтому вам нужно будет ее настроить (создать вспомогательные методы, которые выполнят часть работы, и вызвать их из выражения вместо того, что я делал).
Edit2: BTW: механизм, с помощью которого лямбда может удалить себя, заключается в создании другой лямбды, которая возвращает локальную переменную этого типа. После создания лямбды сохраните его в локальной переменной и запустите код (я не уверен, что это работало бы без дополнительной лямбды)
Edit3: Нет - вы должны использовать трюк делегата, в противном случае константа «замораживается» и не будет обновляться так, как вы этого хотите. Так что код как есть работает.
public class MyEventArgs : EventArgs
{
}
public class EventContainer
{
public event EventHandler<MyEventArgs> MyEvent;
public void Fire()
{
Console.WriteLine("Firing");
if (MyEvent != null)
{
MyEvent(this, new MyEventArgs());
}
Console.WriteLine("Fired");
}
}
class Program
{
static void Main(string[] args)
{
EventContainer container = new EventContainer();
var adder = container.GetType().GetMethod("add_MyEvent");
var remover = container.GetType().GetMethod("remove_MyEvent");
object self = null;
Func<object> getSelf = () => self;
var block = Expression.Block(
// Call something to output to console.
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("Event called")),
// Now call the remove_Event method.
Expression.Call(
Expression.Constant(container), // passing the container as "this"
remover, // And the remover as the method info
Expression.Convert( // we need to cast the result of getSelf to the correct type to pass as an argument
Expression.Invoke( // For the parameter (what to convert), we need to call getSelf
Expression.Constant(getSelf)), // So this is a ref to getSelf
adder.GetParameters()[0].ParameterType) // finally, say what to convert to.
)
);
// Create a lambda of the correct type.
var lambda = Expression.Lambda(
adder.GetParameters()[0].ParameterType,
block,
Expression.Parameter(typeof(object)),
Expression.Parameter(typeof(MyEventArgs)));
var del = lambda.Compile();
// Make sure "self" knows what the delegate is (so our generated code can remove it)
self = del;
// Add the event.
adder.Invoke(container, new object[] { del });
// Fire once - see that delegate is being called.
container.Fire();
// Fire twice - see that the delegate was removed.
container.Fire();
}
}