adi sba
adi sba

Reputation: 621

Reinstantiate static constructor via Reflection

Im using a 3rd party dll for some operations, the instance of the class is static and from time to time is crashing. I was thinking if there is a way to reinstantiate the class via Reflection.

I used DotPeek to check the library and it looks something like this:

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;
            }
        }
    }

When i reference to it i do :

C_SomeWrapper _wrapper=C_SomeWrapper.Instanse

Since is crashing i would like to Destroy() and re-instantiate the constructor. I was thinking maybe is posible to acces _instance and make it null via Reflection. Id like to mention that just Destroy() doesnt work so probably i need to call the constructor and to InitStuff() Any toughts on if its posible or not or maybe some alternatives

Thanks

Upvotes: 1

Views: 200

Answers (2)

Flydog57
Flydog57

Reputation: 7111

The easiest way to do this would be to reset C_SomeWrapper._instance back to null and then let the existing code recreate an instance for you. The example below does this (though it uses a different class name and field name).

I'm working with a type called MyPrivateClass that contains a nullable static field named SomeField (it's a class I had hanging around):

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

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

At the end of that, the private field anObject.SomeField is null.

I wasn't sure how this might work for a class that is declared static. However, it looks like FieldInfo.SetValue(null, null) will work for a static member. As a result, you don't need to instantiate anObject (as shown above).

Upvotes: 1

Maslow
Maslow

Reputation: 18746

Attempt to Re-run a static constructor like so:

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;
}

see also How do I invoke a static constructor with reflection?

however 2 fail, the 3rd just knows the constructor was already run.

Upvotes: 0

Related Questions