0
votes

I am getting this error when i call a non-static Method:

NullReferenceException RealmRecruitment.ResolveRealmFestival () (at Assets/Scripts/Card Manipulation/Realm Cards/Behaviors/RealmRecruitment.cs:14) System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222) Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation. System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232) System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115) RealmCardManager.OnMouseDown () (at Assets/Scripts/Card Manipulation/Realm Cards/RealmCardManager.cs:48) UnityEngine.SendMouseEvents:DoSendMouseEvents(Int32)

Here is the code that calls the individual methods as shown in the RealmCardManager.OnMouseDown () message above which is italicised. (NOTE: I have stripped out non-relevant code):

public class RealmCardManager : MonoBehaviour {
    void OnMouseDown(){     
        Type classType = Type.GetType(CardBehavior);
        ConstructorInfo rCon = classType.GetConstructor(Type.EmptyTypes);
        object cardResult = rCon.Invoke(new object[]{});
        MethodInfo theMethod = classType.GetMethod("Resolve" + CardBehavior, BindingFlags.Instance | BindingFlags.Public);  
        theMethod.Invoke(cardResult, null);
    }
}

The above code calls individual Methods based on the string CardBehavior, in this case the Method called is as follows

public class RealmFestival : MonoBehaviour {
    public PoliticalProblems pP;
    public void ResolveRealmFestival(){
        pP = gameObject.AddComponent<PoliticalProblems>();
        pP.AdjustHeresy(false);
    }
}

Finally this calls the following code:

public class PoliticalProblems: MonoBehaviour {
    public void AdjustHeresy(bool increase){
        if(increase){
            GameData.RealmLevels[2] ++;
        } else {
            GameData.RealmLevels[2] --;
        }
    }
}

If i change AdjustHeresy to Static then the code works perfectly (of course i make the other changes to the calls in RealmFestival). However I cannot have that Method as a Static.

I have tried putting Political Problems on a GameObject and having it stand alone and it still does not change the error message

Thank you in advance

At the request (and with the assistance of) BatteryBackupUnit I have this as the InnerException:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: at at (wrapper managed-to-native) UnityEngine.Component:get_gameObject () at RealmFete.ResolveRealmFete () [0x0001b] in F:\Unity Projects\Online Mulitplayer Code\Assets\Scripts\Card Manipulation\Realm Cards\Behaviors\RealmFete.cs:14 at at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000d0] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222 --- End of inner exception stack trace --- at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000eb] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232 at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115 at RealmCardManager.OnMouseDown () [0x0003e] in F:\Unity Projects\Online Mulitplayer Code\Assets\Scripts\Card Manipulation\Realm Cards\RealmCardManager.cs:49

1
what's the inner exception? That's usually the most interesting part of a TargetInvocationException ;-) - BatteryBackupUnit
I am aware that that is 'trying' to give me the information to resolve this issue but i cannot see what needs to be changed in: MethodInfo theMethod = classType.GetMethod("Resolve" + CardBehavior, BindingFlags.Instance | BindingFlags.Public); - Wibble
A TargetInvocationException occurs when one calls a method through reflection, in case this method throws an exception. The actual exception which caused the TargetInvocationException can be accessed by the InnerException property of the TargetInvocationException. Usually this inner exception contains the necessary information to determine the issue. So please state the content of TargetInvocationException.InnerException. - BatteryBackupUnit
I am sorry, i do not know how to find that... i am currently googling like mad to find a quick-fix - Wibble
Put a breakpoint where the exception occurs. Then when you have the exception you have a look at the exception's InnerException property... Alternatively add a try-catch around the code which throws and in the catch(Exception ex) do Console.WriteLine(ex.InnerException); throw; - BatteryBackupUnit

1 Answers

1
votes

According to the Unity documentation:

Note to experienced programmers: you may be surprised that initialization of an object is not done using a constructor function. This is because the construction of objects is handled by the editor and does not take place at the start of gameplay as you might expect. If you attempt to define a constructor for a script component, it will interfere with the normal operation of Unity and can cause major problems with the project.

In your case, RealmFestival does not need to be a MonoBehaviour anyway: all it does is attach a PoliticalProblems component to a game object. In fact, it doesn't need to be a class either - a static function will suffice in this case (unless you need to keep track of state - but it looks like that can be done by the PoliticalProblems component):

public class CardEffects
{
    public static void ResolveRealmFestival(GameObject gameObject)
    {
        var politicalProblems = gameObject.AddComponent<PoliticalProblems>();
        politicalProblems.AdjustHeresy(false);
    }
}

It's not clear from your code where the string CardBehavior comes from (I assume it's a property of a card object), but if you use an Action<GameObject> instead of a string, you can store a reference to a function instead of having to look it up using reflection:

public class Card
{
    //public string CardBehaviour;
    public Action<GameObject> CardBehaviour;

    public void ApplyCardEffect(GameObject target)
    {
        // Instead of reflection, we can simply invoke the Action directly - assuming it's not null:
        CardBehaviour(target);
    }
}

The card initialization code would change accordingly:

//card.CardBehaviour = "RealmFestival";
card.CardBehaviour = CardEffects.ResolveRealmFestival;