C
C#16mo ago
Rocco

✅ Getting array values through Reflection

I'm making an "interpreter" using reflection but I don't know how to access the value of array elements. I've tried with IEnumerators this way:
C++

//at this point splitFunction[index] should be something like "arrayName[2]"
//nestedValue is the object that contains the array
string[] splitEnumerator = splitFunction[index].Split('[');
FieldInfo field = nestedValue.GetType().GetField(splitEnumerator[0]);
int enumIndex = int.Parse(splitEnumerator[1].Replace("]", ""));
IEnumerator theEnum = ((IEnumerable)field.GetValue(nestedValue)).GetEnumerator();
theEnum.Reset();
for(int m = 0; m < enumIndex; m++)
{
theEnum.MoveNext();
}
nestedValue = theEnum.Current;
C++

//at this point splitFunction[index] should be something like "arrayName[2]"
//nestedValue is the object that contains the array
string[] splitEnumerator = splitFunction[index].Split('[');
FieldInfo field = nestedValue.GetType().GetField(splitEnumerator[0]);
int enumIndex = int.Parse(splitEnumerator[1].Replace("]", ""));
IEnumerator theEnum = ((IEnumerable)field.GetValue(nestedValue)).GetEnumerator();
theEnum.Reset();
for(int m = 0; m < enumIndex; m++)
{
theEnum.MoveNext();
}
nestedValue = theEnum.Current;
But I get this error:
InvalidOperationException: Enumeration has not started. Call MoveNext.
System.Array+ArrayEnumerator.get_Current () (at <f3d0e7ec4efc44199bb22a77b1c8eff4>:0)
HabilityInterpreter.<Execute>g__GetValue|0_1 (System.String _command, HabilityInterpreter+<>c__DisplayClass0_0& ) (at Assets/Scripts/Classes/HabilityInterpreter.cs:179)
HabilityInterpreter.<Execute>g__CheckIfTrue|0_3 (System.String _command, HabilityInterpreter+<>c__DisplayClass0_0& ) (at Assets/Scripts/Classes/HabilityInterpreter.cs:238)
HabilityInterpreter+<Execute>d__0.MoveNext () (at Assets/Scripts/Classes/HabilityInterpreter.cs:57)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <d8d38b92d94a4ff8a91e61d39c6d19cd>:0)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
MatchManager:Update() (at Assets/Scripts/Match/MatchManager.cs:242)
InvalidOperationException: Enumeration has not started. Call MoveNext.
System.Array+ArrayEnumerator.get_Current () (at <f3d0e7ec4efc44199bb22a77b1c8eff4>:0)
HabilityInterpreter.<Execute>g__GetValue|0_1 (System.String _command, HabilityInterpreter+<>c__DisplayClass0_0& ) (at Assets/Scripts/Classes/HabilityInterpreter.cs:179)
HabilityInterpreter.<Execute>g__CheckIfTrue|0_3 (System.String _command, HabilityInterpreter+<>c__DisplayClass0_0& ) (at Assets/Scripts/Classes/HabilityInterpreter.cs:238)
HabilityInterpreter+<Execute>d__0.MoveNext () (at Assets/Scripts/Classes/HabilityInterpreter.cs:57)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <d8d38b92d94a4ff8a91e61d39c6d19cd>:0)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
MatchManager:Update() (at Assets/Scripts/Match/MatchManager.cs:242)
On the line I retrieve the value. (also any other way of making an interpreter in unity that you can think of, please tell)
23 Replies
Doombox
Doombox16mo ago
what language are you interpreting?
Rocco
Rocco16mo ago
My own, i guess
Doombox
Doombox16mo ago
a custom scripting language? fair enough, why are you using reflection in that case?
Rocco
Rocco16mo ago
Because I'm kind of a beginner xD
Doombox
Doombox16mo ago
no real need to, you just need to "translate" your scripting language into managed C#
Rocco
Rocco16mo ago
And didn't know where to start on creating an interpreter
Thinker
Thinker16mo ago
Have you checked out $craftinginterpreters?
Doombox
Doombox16mo ago
if you're new that's going to be a lot proper interpreters are a significant amount of work
Rocco
Rocco16mo ago
Bear in mind that I'm on Unity
Doombox
Doombox16mo ago
you can make simple DSL/scripting languages fairly easily by just reading the script and "converting" it to C#
Rocco
Rocco16mo ago
It's just a tcg game, and I want to be able to code the execution of cards through a text file
Thinker
Thinker16mo ago
You could use C# scripting for that if you wanted
Doombox
Doombox16mo ago
actually compiling code in Unity is a bit of a headache no? though really if you're trying to make your game moddable, there are better ways if you're just writing this purely for yourself, there's no reason not to just write the code in C# to begin with
Rocco
Rocco16mo ago
Nah, i did it that way before, now I want something of a challenge xD For instance?
Doombox
Doombox16mo ago
loading compiled binaries at runtime is a better choice than actually compiling the code you can just frankly use BepinEx or something to save yourself some work, that'll largely handle everything for you it depends on what your overall goal is, if you just want to make a simple DSL for the fun of it then go for it
Rocco
Rocco16mo ago
I don't like having to work with pluggins, even less if they are so specific as to only work with unity, like to make the tools myself
Doombox
Doombox16mo ago
custom scripting lang...
a = [3] // declares a new array with a size of 3, this DSL only supports int arrays.
a[1] = 10
a = [3] // declares a new array with a size of 3, this DSL only supports int arrays.
a[1] = 10
in C#
Dictionary<string,int[]> _arrays = new();
// parse the first line...
_arrays.Add(name, new int[size]);
// parse the second line...
_arrays[name][index] = value;
Dictionary<string,int[]> _arrays = new();
// parse the first line...
_arrays.Add(name, new int[size]);
// parse the second line...
_arrays[name][index] = value;
something like this would work for a very simple DSL if you want a genuine true interpreter, then yeah you'd better read $craftinginterpreters and settle down for a few months of hard work
Rocco
Rocco16mo ago
Right, emm, the objective of the code above is actually to access an array on the GameManager Not to store information
Doombox
Doombox16mo ago
class Foo
{
public int[] Bar = { 1, 2, 3 };
}
//...
var foo = new Foo();
var fld = typeof(Foo).GetField(nameof(Foo.Bar)).GetValue(foo);
var arr = (Array)fieldVal;
var val = (int)arr.GetValue(1);
class Foo
{
public int[] Bar = { 1, 2, 3 };
}
//...
var foo = new Foo();
var fld = typeof(Foo).GetField(nameof(Foo.Bar)).GetValue(foo);
var arr = (Array)fieldVal;
var val = (int)arr.GetValue(1);
not 100% what you're actually trying to achieve, but getting array values is easy enough
Rocco
Rocco16mo ago
It works! thanks!
Accord
Accord16mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.