1

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

adi sba
  • 621
  • 1
  • 12
  • 32
  • "instance of the class is static" That is a oxymoron if I ever saw one. Fields and Functions are either Instance. Or static. They can not be both. Sometimes you might have a single instance case, wich might be what you actually mean. But there is a public constructor so it does not look like that. – Christopher Oct 25 '18 at 19:36
  • 1
    Are you trying to call the static constructor a second time? That seems like a _really_ bad idea; they are written with the idea that they only get called a single time. If you (really) wanted to, you could probably set `C_SomeWrapper._instance` to `null` (via reflection) and then the next time someone accesses `C_SomeWrapper.Instanse`, the internal instance would get rebuilt. Make sure **no one** is trying to access anything to do with the class when you do that. – Flydog57 Oct 25 '18 at 19:41
  • Yes exactly , i want to call second, third an so on every time crashes, could you help me on how to do make Instanse =null via reflection? – adi sba Oct 25 '18 at 19:45
  • 1
    _and from time to time is crashing._ it sounds like you should maybe investigate that and figure out why. It seems like you are trying to duct tape over a bigger problem here. – Matt Burland Oct 25 '18 at 19:49

2 Answers2

1

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).

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • I tried as you sugest but for the var anObject = new MyPrivateClass(); it throws TargetInvocationException + InnerException {"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."} System.Exception {System.AccessViolationException} – adi sba Oct 26 '18 at 08:31
0

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.

Maslow
  • 18,464
  • 20
  • 106
  • 193