Как получить начальное значение поля по Mono Cecil? - PullRequest
2 голосов
/ 17 мая 2019

Я пытаюсь использовать Mono Cecil для получения начального значения в качестве строки открытого поля в DLL.
Вот мой код в библиотеке классов:

namespace ClassLibrary1
{
    public static class Class1
    {
        public static string testField = "abc";
    }
}

Как я могу получить "abc"?

1 Ответ

2 голосов
/ 11 июня 2019

Я не уверен, что Сесил предоставляет API для извлечения этой информации, но поскольку поля экземпляра инициализируются в конструкторе типа и статических полях в статическом конструкторе Вы можете искать магазины в нужном поле. Например, учитывая этот класс:

  .method private hidebysig specialname rtspecialname static 
        void .cctor () cil managed 
    {
        // Method begins at RVA 0x205f
        // Code size 21 (0x15)
        .maxstack 8

        IL_0000: ldstr "Foo"
        IL_0005: stsfld string Program::'value'
        IL_000a: call string Program::MyFunction()
        IL_000f: stsfld string Program::value2
        IL_0014: ret
    } // end of method Program::.cctor

Вы можете сделать что-то вроде:

using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace CecilRetrieveInitializer
{
    class Program
    {
        static Program()
        {
            Console.WriteLine("In cctor..");
        }

        static void Main(string[] args)
        {
            using (var a = AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location))
            {
                var t = a.MainModule.GetType("CecilRetrieveInitializer.Program");
                var f = t.Fields.SingleOrDefault(c => c.Name == "value");
                Console.WriteLine(InitialValue(t, f));
                Console.WriteLine(InitialValue(t, t.Fields.SingleOrDefault(c => c.Name == "value2")));
            }

            string InitialValue(TypeDefinition t, FieldDefinition f)
            {
                var cctor = t.Methods.SingleOrDefault(m => m.Name == ".cctor");
                if (cctor == null)
                    throw new Exception("no field initialization...");

                var store = cctor.Body.Instructions.SingleOrDefault(i => i.OpCode == OpCodes.Stsfld && i.Operand == f);
                if (store.Previous.Operand.GetType() != typeof(string))
                    return store.Previous.Operand.ToString();

                return (string) store.Previous.Operand;
            }
        }

        static string MyFunction() => "Bar";

        public static string value = "Foo";
        public static string value2 = MyFunction();
        public const string value3 = "Bar";
    }
}

Имейте в виду, что поле может быть инициализировано значением non-const , в этом случае вы, вероятно, не сможете (легко) получить значение (см. value2 ) .

Также обратите внимание, что если вы объявите свое поле как const , вы можете использовать Constant свойство:

f = t.Fields.SingleOrDefault(c => c.Name == "value3");
Console.WriteLine(f.Constant);
...