Ниже немного контекстной информации ... У меня есть Клиент, который может выполнить метод, предоставляемый сервером, только если этот метод совпадает с этим delegate
public delegate object[] MyMethod (int code, object[] parameters);
, так что ... для Например, если я хочу выставить новый метод, который выполняет сумму двух целых чисел, я должен сделать что-то вроде этого:
private static object[] Sum(int code, object[] parameters)
{
int firstNumber = int.Parse(parameters[0].ToString()),
secondNumber = int.Parse(parameters[1].ToString());
return new object[1] { firstNumber + secondNumber };
}
Каждый вид проверок (нулевые, целочисленные проверки и т. д.) избегают для простоты , Затем в инициализаторе класса я должен сделать что-то вроде
Register(Sum);
, где Register
принимает делегатов MyMethod и просто регистрирует метод (который должен быть выполнен с этим делегатом), и этот метод должен иметь два параметра целых чисел типа (int32 in. net) в качестве входных данных и один параметр целочисленного типа (int 32) в качестве выходного результата.
Пока ничего сложного ... Но я хотел бы сделать некоторые дополнительно и реализовать что-то более читабельное ...
Моя цель - позволить разработчику написать что-то подобное вместо этого:
[ExternalOperationContract]
public static int Sum(int a, int b) => a + b;
, где [ExternalOperationContractAttribute]
- это пользовательский атрибут, созданный ad ho c. То, что я хотел бы сделать, это получить все методы с Reflection, помеченными этим атрибутом, создать DynamicMethod
с тем же параметром ввода и вывода делегатов и ввести инструкции так, чтобы новый метод вел себя точно так же, как и метод ExternalOperationCOntractAttribute.
Я обнаружил пространство имен System.Reflection.Emit и думаю, что это что-то полезное для этой области. Поэтому я попытался реализовать что-то, но с плохими результатами, и, честно говоря, код Франкенштейна взял некоторые фрагменты кода здесь и там в сети. Ниже приведена часть:
public static void Main()
{
Type[] sumArgs = { typeof(int), typeof(object[]) };
// Create a dynamic method with the name "Sum", a return type
// of object[], and two parameters whose types are specified by the
// array helloArgs. Create the method in the module that
// defines the Test class.
DynamicMethod hello = new DynamicMethod("Sum",
typeof(object[]),
sumArgs,
typeof(Test).Module);
// Get the overload of Console.WriteLine that has one
// String parameter.
MethodInfo myMethod =
typeof(Test).GetMethod("Sum");
ILGenerator ilgen = hello.GetILGenerator();
var il = ilgen;
il.Emit(OpCodes.Ldarg_0);
LocalBuilder arr = il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(string));
il.Emit(OpCodes.Stloc, arr);
il.Emit(OpCodes.Ldloc, arr);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stelem_I4);
il.Emit(OpCodes.Ldloc, arr);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Call, myMethod);
il.Emit(OpCodes.Ret);
// Create a delegate that represents the dynamic method. This
// action completes the method, and any further attempts to
// change the method will cause an exception.
MethodCallBack hi =
(MethodCallBack)hello.CreateDelegate(typeof(MethodCallBack));
Register(hi);
Console.Read();
}
Итак, мои вопросы:
- Как мне взять элементы из входного массива, привести их к подходящему типу и отправить их в DynamicMethod (я думаю, что эта часть выполняется с помощью инструкции
OpCodes.Call
)? - Как я могу вернуть более одного объекта в массив объектов, используя пространство имен Emit?
- В любом случае, объяснение предпочтительнее, чем прямое решение :) даже способ директивы программирования может быть оценен. Я ожидаю некоторой конструктивной критики типа «Зачем усложнять то, что легко?» ... Да, я знаю, и мне тоже интересно :) Может быть, чтобы увидеть и узнать что-то новое и попытаться сделать код более читабельным и тонким, что для разработчика совсем не плохо.
Заранее большое спасибо.