Я хочу подписаться на любое событие, существующее в данном объекте, тип которого заранее неизвестен. Я создаю обработчик событий во время выполнения, используя System.Linq.Expressions.Expression.
Код, который у меня есть (см. ниже), почти работает... Но, к сожалению, есть некоторые события, которые не следуют шаблону отправителя, EventArgs, и я не могу это контролировать. Некоторые из них имеют параметры ref, и попытка записать их обратно (что, к сожалению, мне нужно сделать) вызывает System.ArgumentException: 'Невозможно привязаться к целевому методу, поскольку его подпись или прозрачность безопасности несовместимы с подписью метода тип делегата.' в Lambda.Compile(). Альтернативой было бы переписать его для генерации IL, но я бы предпочел этого избежать.
Событие:
public delegate void SomeEventDelegate(ref int a, int b);
public event SomeEventDelegate SomeEvent;
Динамически создаваемая лямбда-выражение:
(ref int a, int b) =>
{
var __values__ = new[] { a, b };
Action.Invoke("SomeEvent", new[] { "a", "b" }, __values__);
a = (int)__values__[0]; //this causes an exception in `lambda.Compile()`
}
Полный пример:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AgileObjects.ReadableExpressions; //optional, converts generated expression to more readable string
class PseudoControl
{
public delegate void SomeEventDelegate(ref int a, int b);
public event SomeEventDelegate SomeEvent;
public void RaiseEvents()
{
var a = 0;
var b = 0;
SomeEvent?.Invoke(ref a, b);
}
}
public class ControlExtender
{
public object ExtendedControl { get; set; }
public void SubscribeToAllEvents()
{
foreach (var ei in ExtendedControl.GetType().GetEvents(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public))
{
SubscribeToEvent(ei);
}
}
private void SubscribeToEvent(EventInfo ei)
{
var handlerType = ei.EventHandlerType;
var eventParams = handlerType.GetMethod("Invoke").GetParameters();
//lambda: (p1, p2, ...) => RaiseObjectEvent(ei.Name, new[] { pname1, pname2, ... }, new[] { pval1, pval2, ...});
var parameters = eventParams
.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var action = new Action(RaiseObjectEvent);
var constEventName = Expression.Constant(ei.Name);
var arrPNames = Expression.NewArrayInit(typeof(string), parameters.Select(p => Expression.Constant(p.Name)));
var arrPValues = Expression.NewArrayInit(typeof(object), parameters.Select(p => Expression.Convert(p, typeof(object))));
var statements = new List();
var varPValues = Expression.Variable(typeof(object[]), "__values__");
statements.Add(Expression.Assign(varPValues, arrPValues));
statements.Add(Expression.Call(Expression.Constant(action), action.GetType().GetMethod("Invoke"), constEventName, arrPNames, varPValues));
//handle `ref` parameters being written into
for (int i = 0; i < parameters.Length; i++)
{
var p = parameters;
if (p.IsByRef)
{
var value = Expression.ArrayAccess(varPValues, Expression.Constant(i));
var unbox = Expression.Convert(value, p.Type);
var assign = Expression.Assign(p, unbox); // { a = 1; b = 2; };
control.RaiseEvents();
}
}
Подробнее здесь: https://stackoverflow.com/questions/790 ... -parameter
Динамически создаваемый обработчик событий, который записывает его в параметр ref. ⇐ C#
Место общения программистов C#
1728562432
Anonymous
Я хочу подписаться на любое событие, существующее в данном объекте, тип которого заранее неизвестен. Я создаю обработчик событий во время выполнения, используя System.Linq.Expressions.Expression.
Код, который у меня есть (см. ниже), почти работает... Но, к сожалению, есть некоторые события, которые не следуют шаблону отправителя, EventArgs, и я не могу это контролировать. Некоторые из них имеют параметры ref, и попытка записать их обратно (что, к сожалению, мне нужно сделать) вызывает System.ArgumentException: 'Невозможно привязаться к целевому методу, поскольку его подпись или прозрачность безопасности несовместимы с подписью метода тип делегата.' в Lambda.Compile(). Альтернативой было бы переписать его для генерации IL, но я бы предпочел этого избежать.
Событие:
public delegate void SomeEventDelegate(ref int a, int b);
public event SomeEventDelegate SomeEvent;
Динамически создаваемая лямбда-выражение:
(ref int a, int b) =>
{
var __values__ = new[] { a, b };
Action.Invoke("SomeEvent", new[] { "a", "b" }, __values__);
a = (int)__values__[0]; //this causes an exception in `lambda.Compile()`
}
Полный пример:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AgileObjects.ReadableExpressions; //optional, converts generated expression to more readable string
class PseudoControl
{
public delegate void SomeEventDelegate(ref int a, int b);
public event SomeEventDelegate SomeEvent;
public void RaiseEvents()
{
var a = 0;
var b = 0;
SomeEvent?.Invoke(ref a, b);
}
}
public class ControlExtender
{
public object ExtendedControl { get; set; }
public void SubscribeToAllEvents()
{
foreach (var ei in ExtendedControl.GetType().GetEvents(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public))
{
SubscribeToEvent(ei);
}
}
private void SubscribeToEvent(EventInfo ei)
{
var handlerType = ei.EventHandlerType;
var eventParams = handlerType.GetMethod("Invoke").GetParameters();
//lambda: (p1, p2, ...) => RaiseObjectEvent(ei.Name, new[] { pname1, pname2, ... }, new[] { pval1, pval2, ...});
var parameters = eventParams
.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var action = new Action(RaiseObjectEvent);
var constEventName = Expression.Constant(ei.Name);
var arrPNames = Expression.NewArrayInit(typeof(string), parameters.Select(p => Expression.Constant(p.Name)));
var arrPValues = Expression.NewArrayInit(typeof(object), parameters.Select(p => Expression.Convert(p, typeof(object))));
var statements = new List();
var varPValues = Expression.Variable(typeof(object[]), "__values__");
statements.Add(Expression.Assign(varPValues, arrPValues));
statements.Add(Expression.Call(Expression.Constant(action), action.GetType().GetMethod("Invoke"), constEventName, arrPNames, varPValues));
//handle `ref` parameters being written into
for (int i = 0; i < parameters.Length; i++)
{
var p = parameters[i];
if (p.IsByRef)
{
var value = Expression.ArrayAccess(varPValues, Expression.Constant(i));
var unbox = Expression.Convert(value, p.Type);
var assign = Expression.Assign(p, unbox); // { a = 1; b = 2; };
control.RaiseEvents();
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79074350/dynamically-created-event-handler-that-writes-ito-a-ref-parameter[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия