Почему вызов DynamicMethod с экземпляром моего собственного класса вызывает исключение?
-
19-09-2019 - |
Вопрос
Я изучаю CIL, создавая свои собственные функции во время выполнения с помощью Reflection.Emit
.Я на самом деле удивлен, насколько легко все было до сих пор, но я столкнулся с чем-то, чего не могу догадаться, и не могу найти ничего относительного в документации.
Я пытаюсь создать функцию, которая просто печатает очень простой класс, который я определил.Если я изменю свой код для печати string
скажем, он работает, но всегда не запускается, когда я передаю экземпляр своего класса A
.
Что странно, я могу закомментировать тело своей функции, но оно все равно терпит неудачу с TargetInvocationException
.Это должно быть довольно просто, но я не понимаю, в чем дело!
class A
{
public override string ToString()
{
return "AAA!";
}
}
class Program
{
static void Main(string[] args)
{
DynamicMethod func = new DynamicMethod("func", null, new Type[] { typeof(A) });
ILGenerator il = func.GetILGenerator();
//il.Emit(OpCodes.Ldarg_0);
//il.Emit(OpCodes.Box, typeof(A));
//il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(A) }));
il.Emit(OpCodes.Ret);
func.Invoke(null, new object[] { new A() });
Console.Read();
}
}
Что я делаю так неправильно, что это вызывает исключение?Почему это происходит только с моими занятиями?
Решение
Проблема проста, но не очевидна.Для начала не ограничивайте аргумент, как уже указывалось.Но настоящая проблема в том, что класс А не является публичным.Привязка по умолчанию для используемой вами функции Invoke (а не полная) заключается в поиске только общедоступных методов.Поскольку A является закрытым классом, это означает, что он не может найти вашу функцию (удивительно, я знаю) и терпит неудачу.
Другие советы
На самом деле это было довольно глупо.Я потратил на это несколько часов, но когда я последовал совету Лорана Этьембля и создал делегата, полученное мной исключение сообщило мне, что мой класс A не является общедоступным.
Решение:Добавьте публичное ключевое слово перед class A
.Работает отлично.я знал это должно было быть что-то безумно простое.
Во-первых, вы не должны испускать Box
код операции с тех пор A
это класс и его не нужно упаковывать.Упаковка предназначена только для типов значений.
Во-вторых. Причина сбоя заключается в том, что у метода нет разрешения на доступ к классу A (он не является общедоступным).Либо сделай A
public
ИЛИ Вы можете указать JIT-компилятору пропустить проверки видимости, используя этот конструктор и прохождение true
к параметруskipVisibility.