Я пытаюсь создать делегаты с открытым экземпляром для методов, которые имеют общую сигнатуру, но определены для множества разных и не связанных типов. Эти методы помечены пользовательским атрибутом, и во время выполнения я ищу все методы, помеченные этим атрибутом, чтобы создать делегатов из их MethodInfo
s. Например, учитывая делегата:
delegate void OpenActionDelegate(object instance, float someParam);
Я бы хотел сопоставить методы:
void Foo.SomeAction(float someParam);
void Bar.SomeOtherAction(float someParam);
Где Foo
и Bar
- совершенно не связанные классы. Вооружившись MethodInfo
для любого метода, я бы хотел в конечном итоге получить открытый делегат, например, так:
MethodInfo fm = typeof(Foo).GetMethod("SomeAction", BindingFlags.Public | BindingFlags.Instance);
MethodInfo bm = typeof(Bar).GetMethod("SomeOtherAction", BindingFlags.Public | BindingFlags.Instance);
OpenActionDelegate fd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), fm);
OpenActionDelegate bd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), bm);
Проблема, с которой я сталкиваюсь, заключается в типе явной спецификации экземпляра в делегате. Поскольку эти методы не имеют гарантированного базового типа, на котором они будут определены, я попытался просто установить object
. Но попытка связать MethodInfo
не удалась, предположительно, потому что типы параметров не являются ковариантными при связывании делегатов. Переключение подписи делегата на параметр param типа Foo
или Bar
работает для привязки соответствующего MethodInfo
.
Я не верю, что на самом деле возможно связать открытый делегат подобным образом, потому что тогда явный параметр экземпляра не будет подходящего типа для вызова метода. Что меня беспокоит, так это , можно связать закрытый делегат с MethodInfo
любого объявленного типа, поскольку это не включает проблемный тип экземпляра. Например, я могу привязать закрытые делегаты к null
экземплярам, а затем использовать GetField("_target").SetValue(del, instance)
для делегатов непосредственно перед их вызовом. Но это отчасти хакерски.
Теперь, в случае, если есть альтернативные решения, я пытаюсь это сделать, чтобы избежать выделения кучи и упаковки типов значений при непосредственном вызове MethodInfo
s, т.е.:
someActionInfo.Invoke(instance, new object[] { someParam });
Это вызывает упаковку типа float
, и массив object[]
выделяется в куче, причем оба медленно генерируют мусор в куче для вызова, выдаваемого в противном случае.