Восстановить статический конструктор с помощью Reflection - PullRequest
0 голосов
/ 25 октября 2018

Я использую сторонний dll для некоторых операций, экземпляр класса статичен и время от времени дает сбой.Я думал, есть ли способ восстановить класс с помощью Reflection.

Я использовал DotPeek для проверки библиотеки, и она выглядит примерно так:

public class C_SomeWrapper
    {
        private static C_SomeWrapper _instance;
        public C_SomeWrapper()
        {
            InitStuff();
        }
        void InitStuff()
        {

        }
        public void Destroy()
        {
            C_SomeWrapper._instance = (C_SomeWrapper)null;
        }
        public static C_SomeWrapper Instanse
        {
            get
            {
                if (C_SomeWrapper._instance == null)
                    C_SomeWrapper._instance = new C_SomeWrapper();
                return C_SomeWrapper._instance;
            }
        }
    }

Когда я ссылаюсь на него, яdo:

C_SomeWrapper _wrapper=C_SomeWrapper.Instanse

Поскольку происходит сбой, я хотел бы уничтожить () и создать экземпляр конструктора.Я думал, что возможно получить доступ к _instance и сделать его нулевым через Reflection.Я хотел бы отметить, что просто Destroy () не работает, поэтому, вероятно, мне нужно вызвать конструктор и InitStuff (). Любые проблемы, если это возможно или нет, или, возможно, некоторые альтернативы

Спасибо

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Попытка повторно запустить статический конструктор, например, так:

void Main()
{
    var t = typeof(AmStaticHearMeRoar);
    TryIt(t,RunConstructor);
    TryIt(t,RunTypeInitializer);
    TryIt(t, RunClassConstructor);
}

static void TryIt(Type t, Action<Type> f){
    Console.WriteLine("value is:" + AmStaticHearMeRoar.State);
    AmStaticHearMeRoar.Reset();
    try{
        f(t);
        Console.WriteLine("constructor rerun, value is:" + AmStaticHearMeRoar.State);
    } catch(Exception ex){
        ex.Dump();
        Console.WriteLine("constructor rerun?, value is:" + AmStaticHearMeRoar.State);
    }
    finally{
        AmStaticHearMeRoar.Reset();
    }

}

static void RunConstructor(Type t) {
    var m = t.GetConstructor(BindingFlags.Static | BindingFlags.NonPublic, System.Type.DefaultBinder, System.Type.EmptyTypes, null);
    m.Dump();
    m.Invoke(new object[] {});
}
static void RunTypeInitializer(Type t){
    t.TypeInitializer.Invoke(BindingFlags.NonPublic | BindingFlags.Static, System.Type.DefaultBinder, new object[] {},System.Globalization.CultureInfo.DefaultThreadCurrentCulture);
}
static void RunClassConstructor(Type t) {
    // only works if it hasn't been run =(
    RuntimeHelpers.RunClassConstructor(t.TypeHandle);
}
// Define other methods and classes here

public static class AmStaticHearMeRoar
{
    static int myStaticState;
    static AmStaticHearMeRoar()
    {
        myStaticState = 3;
    }
    public static void Reset() {
        myStaticState = 0;
    }
    public static int State => myStaticState;
}

см. Также Как вызвать статический конструктор с отражением?

однако 2 не удаются3-й просто знает, что конструктор уже был запущен.

0 голосов
/ 25 октября 2018

Самый простой способ сделать это - сбросить C_SomeWrapper._instance обратно на ноль и затем позволить существующему коду воссоздать экземпляр для вас.Пример ниже делает это (хотя он использует другое имя класса и имя поля).

Я работаю с типом с именем MyPrivateClass, который содержит статическое поле, допускающее обнуляемое имя с именем SomeField (это класс Iимел место):

   var myType = typeof(MyPrivateClass);
   var anObject = new MyPrivateClass();

   var myField = myType.GetField("SomeField", BindingFlags.Static | BindingFlags.NonPublic);
   myField.SetValue(anObject, null);

В конце этого приватное поле anObject.SomeField является нулевым.

Я не был уверен, как это может работать для класса, который объявлен static.Тем не менее, похоже, что FieldInfo.SetValue(null, null) будет работать для статического члена.В результате вам не нужно создавать экземпляр anObject (как показано выше).

...