Вземете дефиниция на член от справка в Mono.Cecil

Забелязах, че препратките към поле или метод в определени типове методи (например метод в общ тип) ще бъдат от тип FieldReference, а не FieldDefinition, въпреки че полето (или методът) е в същия модул, в същия тип. Как мога да взема FieldDefinition от това FieldReference?

Опитах module.Import и module.MetadataResolver.Resolve, но и двете не работят.

Продължение на този въпрос, но по-обща.

РЕДАКТИРАНЕ:

Прост общ клас:

public class HelperClass<T>
{
    private int _someInt;

    void SomeMethod(int i)
    {
        _someInt = i;
    }
}

Тялото на SomeMethod съдържа:

...
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfdl System.Int32 HelperClass`1<T>::_someInt
....

Операндът на кода на операцията IL_000a обикновено трябва да бъде FieldDefinition, в крайна сметка той е в същия модул. Но тъй като предполагам, че HelperClass е общо, операндът е FieldReference, който няма да се разреши, мога просто да се надявам да сравня пълните имена, за да намеря действително FieldDefinition.

В този случай това не е голям проблем, но когато препратката е към други членове в други общи типове, сигурен съм, че има по-добър начин да го направите от изброяването на всички типове, за да намерите дефиницията.

РЕДАКТИРАНЕ:

HelperClass<> е от модул, който се зарежда по време на изпълнение от AssemblyDefinition.ReadAssembly, тогава .Resolve() връща null вместо FieldDefinition.

АКТУАЛИЗАЦИЯ:

Оказа се, че тъй като променям името на полето в общия тип, препратката се къса и Resolve() връща нула. Все още търсите прилично решение за това.


person mrahhal    schedule 05.01.2015    source източник
comment
Извикването на Resolve() за препратката не работи ли? (Т.е. var myFieldDefinition = myFieldReference.Resolve();)   -  person rileywhite    schedule 06.01.2015
comment
@rileywhite Не, връща нула. Първоначално си помислих, че това трябва да е дефиниция, но мисля, че препратките към членове на генерични типове се обработват по различен начин в Cecil.   -  person mrahhal    schedule 06.01.2015
comment
Бихте ли публикували код, който възпроизвежда това, което виждате?   -  person rileywhite    schedule 07.01.2015
comment
@rileywhite, вижте редакцията, моля.   -  person mrahhal    schedule 07.01.2015


Отговори (1)


Актуализация:

Промених кода, за да разделя типовете в различни проекти в различни решения. За съжаление, все още не мога да възпроизведа проблема, но съм готов да продължа да опитвам, ако ще помогне.

Мога да разреша препратката към типа със следния код. Ако сте в състояние да предоставите повече подробности за репродукция, ще бъда готов да пробвам още веднъж :-)

Това е единственият тип в сборка, наречена TargetLibrary.dll. Компилирах го в собствено решение и копирах сборката в C:\Temp.

public class HelperClass<T>
{
    private int _someInt;

    void SomeMethod(int i)
    {
        _someInt = i;
    }
}

Този код е в различен сбор, който е компилиран в конзолен exe файл в рамките на собственото си решение.

class Program
{
    static void Main(string[] args)
    {
        var module = AssemblyDefinition.ReadAssembly(@"C:\Temp\TargetLibrary.dll").MainModule;

        Console.WriteLine("For HelperClass<>");
        var helperClass = module.Types[1];
        var someMethod = helperClass.Methods[0];
        var someMethodBody = someMethod.Body;
        foreach (var instruction in someMethodBody.Instructions)
        {
            Console.WriteLine(
                "{0}\t{1}\t{2}",
                instruction.Offset,
                instruction.OpCode.Code,
                instruction.Operand == null ? "<null>" : string.Format("{0} / {1}", instruction.Operand.GetType().FullName, instruction.Operand.ToString()));

            var fieldReference = instruction.Operand as FieldReference;
            if (fieldReference != null)
            {
                var fieldDefinition = fieldReference.Resolve();
                Console.WriteLine(
                    "\t\tResolved field reference operand: {0} / {1}",
                    fieldDefinition.GetType().FullName,
                    fieldDefinition.ToString());
            }
        }
    }
}

Изпълнението на това произвежда следния изход.

For HelperClass<>
0       Ldarg_0 <null>
1       Ldarg_1 <null>
2       Stfld   Mono.Cecil.FieldReference / System.Int32 TargetLibrary.HelperClass`1<T>::_someInt
                Resolved field reference operand: Mono.Cecil.FieldDefinition / System.Int32 TargetLibrary.HelperClass`1::_someInt
7       Ret     <null>
person rileywhite    schedule 08.01.2015
comment
Благодаря! Проблемът е, че препратката всъщност е от зареден модул, говоря за модул, който заредих по време на изпълнение. Това е, когато Resolve() връща нула, вашият пример работи с общ тип от изпълняващия се асембли и нямам представа защо това работи, докато другото не. - person mrahhal; 08.01.2015
comment
Хмм... изглежда, че резолверът на асемблиране, свързан с препратката, може да има проблеми с намирането на асемблирането, което е странно, защото вече сте използвали резолвера, за да заредите асемблирането. Ще го пробвам отново, когато имам няколко минути. - person rileywhite; 08.01.2015
comment
Точно моите мисли. За да направя нещата по-ясни, използвам AssemblyDefinition.ReadAssembly за зареждане на MainModule и продължавам оттам. Благодаря за помощта. - person mrahhal; 08.01.2015
comment
@mrahhal, актуализирах кода въз основа на вашите отзиви. Има ли нещо друго, за което се сещате, че може да правите по различен начин? Използвам Mono.Cecil версия 0.9.5.4, инсталирана от NuGet във Visual Studio 2013 и .NET 4.5, в случай че има значение. - person rileywhite; 11.01.2015
comment
благодаря за цялата помощ. Открих проблема в другия си въпрос тук Заявявам, че всъщност променям имената на някои от полетата, докато вървя. Открих, че когато направя това, методът .Resolve връща нула. Приех отговора ви, но имате ли предложение как да направя това, без да нарушавам тази препратка? Разбира се, мога да измисля решение, но бих искал да потърся просто, преди да тръгна по обратния път. - person mrahhal; 11.01.2015