#c# #cil
#c# #cil
Вопрос:
как указано в названии. Тем не менее, я пытаюсь это сделать:
delegate char[] FieldDelegate();
private FieldDelegate Get_InternalBuffer(StringBuilder sb)
{
var sbType = sb.GetType();
var fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("GetField", typeof(char[]), new Type[0], true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.ldflda, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
Короче говоря, я понятия не имею, почему. Я проверил IL-код класса, содержащего только «char[] buffer», чтобы имитировать то, что я здесь делаю, и на самом деле в нем правильно указано следующее: «IL_0006: ret» как одна IL_instruction, так что я делаю не так?
Любая помощь была бы потрясающей!
с наилучшими пожеланиями
Комментарии:
1. Это похоже на то, что вы задали вопрос самому себе. Я имею в виду, что здесь явно не хватает информации. Вопрос нуждается в большей ясности
2. что еще вам нужно? ОТРЕДАКТИРОВАЛ делегат, чтобы показать, какой из них я пытаюсь создать, sry, я этого не видел
Ответ №1:
Я не уверен на 100%, чего вы на самом деле пытаетесь достичь, но обязательно ли это быть динамическим / использовать Emit API?
Если нет, вот рабочий подход к отражению:
private static Func<char[]> Get_InternalBuffer_Reflection_Only(StringBuilder stringBuilder)
{
Type sbType = stringBuilder.GetType();
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
Func<char[]> func = () => (char[])fieldInfo.GetValue(stringBuilder);
return func;
}
Есть много предостережений, о которых нужно знать:
- Вы фиксируете
StringBuilder
внутри делегата / функции и, таким образом, привязываете его время жизни к возвращаемому делегату / функции. - Вам придется оплачивать накладные расходы на излучение / отражение каждый раз, когда вы хотите использовать новый
StringBuilder
Редактировать:
Для повышения производительности я думаю, вы можете либо сделать это с помощью Expression, либо Emit . С помощью IL я не уверен, как вы будете фиксировать StringBuilder
параметр в вашем динамически создаваемом методе, но вы можете немного изменить свой делегат, чтобы получить тот же результат.
Просматривая ваш код еще раз, причина, по которой он не работает, заключается в том, что вы вызываете Ldfld
, когда в вашем методе на самом деле ничего нет в стеке. В FieldInfo
одиночку просто описывается, как добраться до значения, вам все равно нужна ссылка на объект для извлечения значения.
Изменив свой делегат, вы можете сделать это:
delegate char[] FieldDelegate(StringBuilder sb);
private static FieldDelegate Get_InternalBuffer()
{
Type sbType = typeof(StringBuilder);
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("DynamicGetChunkChars",
typeof(char[]), new Type[] { sbType }, true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.Ldarg_0);
ig.Emit(OpCodes.Ldfld, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
static void Main(string[] args)
{
var sb = new StringBuilder("test123");
FieldDelegate getBuffer = Get_InternalBuffer();
char[] ret = getBuffer(sb);
Console.ReadLine();
}
Вам нужно будет вызвать возвращаемый метод с StringBuilder
помощью .
Это также означает, что теперь вы можете кэшировать возвращенный метод и использовать его повторно.
Комментарии:
1. Да, я хочу, чтобы EmitApi для производительности избегал кода отражения, поскольку мне придется использовать этот метод в цикле!
2. Чистый код отражения здесь в 4 раза снизил бы производительность.
3. Замечательно, большое спасибо! я просто не мог правильно понять, почему вам нужно передать этот экземпляр Stringbuilder в динамический метод и почему мой подход не работает, поскольку я тоже говорю. «sbBuffer. GetType()» это должно быть на самом деле в моей голове, по крайней мере, работать как ваше решение? по-видимому, нет: D большое спасибо!