Late binding using reflection in C#

Hey everyone,

I’m pulling my hair out over this one. What I’m trying to do is create a variable of an at compile-time-unkown type using reflection. More specifically, a variable called levelScript, which can be of type Level1, Level2, etc. Here’s my code:

using UnityEngine;
using System;
using System.IO;
using System.Reflection;

levelScriptName = "Level" + (_level).ToString(); //_level is an int being read from a file.
Type levelType = playerScript.gameObject.GetComponent(levelScriptName).GetType(); //returns Level1 like it should
Debug.Log(levelType); //also returns Level1

levelType levelScript = playerScript.gameObject.GetComponent(levelScriptName) as levelType; //gives compiling error:
error CS0246: The type or namespace name `levelType' could not be found. Are you missing a using directive or an assembly reference?

Any help would be much appreciated!

-Patrick

leveltype is a instance of the class Type and not a Typename. if you want to cast the type you need something like this:

var myLevelScriptComponent = playerScript.gameObject.GetComponent(levelScriptName);
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(t);
object castedObject = castMethod.Invoke(null, new object[] { myLevelScriptComponent});

But Iam not sure if you really understand what you do.

Hey Marrrk,

Thanks for your quick reply. You’re right in that I’m not completely clear on how this works (I thought I was, but obviously that’s not the case. :wink: ) This is actually my first time working in C# with the System directive from scratch and I just learned about reflection today. I’ll check out the link and solution you suggested tonight. Thanks again!

Ok, call me crazy, but I’ve never been so stuck on anything. I just can’t figure out how to do this. Any suggestions on a good approach for this/ where to look? Marrrk, I checked out your example but I can’t seem to wrap my head around it. =/

What exactly do you want to do?

Hey Marrrk,

In a C#-script I want to store the player’s ‘levelScript’ into a variable so I can call methods on it. However, this script can be of type Level1, Level2, Level3, etc., which, as you might’ve guessed, depends on the level the player is currently in and is thus not known at compile-time. (Yes, this means we have a different ‘player’ prefab for each level. Though we plan on moving the script to a levelManager object, the same problem will exist.)This is what we have now for testing purposes:

Level1 levelScript = gameObject.GetComponent<Level1>();
levelScript.doSomeAwesomeShizzle();

Of course in JavaScript this problem could be easily solved by using implicit casting:

var currentLevel:int = 1;
var levelScript;

function Start(){
     levelScript = gameObject.GetComponent("Level"+currentLevel.ToString());
}

Ok, strange way to do things, but ok, I guess you have your reasons to do something like this.
C# is not a good option in this case, similar simple like the JS script is not possible.

You have 2 options here:

  1. Inherit all your levels from a common interface and cast your component to this interface and use this interface. This has the benefit that you know at compile time what the interface is, but your component needs to implement the interface fully, which is maybe not the thing you want.

  2. Retrive the type of your component, search your method you want to call (yourType.GetMethod(“doSomeAwesomeShizzle”)) and execute this method on your component (myMethod.Invoke(myInstance, new object[ ] { param1, param2, praramN }))

I would definitely avoid using reflection for this. Not because it can’t/won’t work - it’ll work great, but because it’ll be incredibly messy, unneccesary, make debugging things as simple as typos significantly more difficult, and more importantly - it’s just plain poor practice.

I would definitely go with Marrrk’s first suggestion - use a C# interface or a common root class. I would suggest a common root class, since GetComponent doesn’t play nicely with C# Interfaces. Make sure you mark all your functions as protected virtual and override like so…

public class LevelBase : Monobehavior {
	void CannotOverride(){
		
	}
	
	public void StillCannotOverride(){
		Debug.Log("Public StillCannotOverride called on LevelBase!");
	}
	
	protected virtual void CanOverride(){
		
	}
	
	public virtual void CanOverride(){
		Debug.Log("Public CanOverride called on LevelBase!");
	}
}

public class LevelOne : LevelBase {
	void CannotOverride(){
		
	}
	
	new public void StillCannotOverride(){
		Debug.Log("Public StillCannotOverride called on LevelOne!");
	}
	
	protected override void CanOverride(){
		
	}
	
	public override void CanOverride(){
		Debug.Log("Public CanOverride called on LevelBase!");
	}
}

If you did something like:

LevelBase levelScript = GetComponent(); - and the returned component was LevelOne you could still then…

levelScript.StillCannotOverride(); // This would Debug.Log(“Public StillCannotOverride called on LevelBase!”)
levelScript.CanOverride(); // This would Debug.Log(“Public CanOverride called on LevelBase!”);

So yea, I highly suggest a common base class with virtual/override functions until you get a better overall solution to the problem.

Hi, and thanks for both your inputs!

Kyle, though it looks like a very elegant solution, I probably should’ve mentioned all LevelScript scripts are in JS, and so far we haven’t had a need to extend anything yet, keeping everything compact and almost in a WYSIWYG kind of fashion (ie: no hidden/ extended methods or members). So if possible I’d like to keep it that way just for consistency’s sake. =) (And yes, I’m perfectly aware that in most cases you’ll want to extend from base classes. This has been thoroughly discussed within our team.)

Marrrk, your second approach works perfectly, thanks! =) I’m just wondering if I can also set variables through this approach using something like GetField/ SetField… runs to msdn

Thanks a bunch!

-Patrick