When I first started programming my TemporalWars 3D game engine in 2008, very few interfaces were used. However, as the program grew in complexity I quickly realize the importance of compartmentalizing code and abstracting the connections to those units using Interfaces. For those who are not aware of what an Interface is, an Interface is simply the description of the connections (properties, methods, events) you are making public to some component or class. As your program grows in complexity, you quickly will appreciate the power interfaces bring to your project. So, some of you are reading this saying, I already know that! What the point? Well, lets talk about Late-Binding first and connect how Interfaces become useful in this situation.
Early-Binding is the typical way of programming, where you add some reference to an assembly at the top of the code-base, using C# as an example, and compile the program. With Early-Binding the program is aware of the assembly before compilation. In comparison, Late-Binding is binding some assembly after a program is compiled, which the original program was not aware of or didnt have access to the base code during the original compilation.
In the TemporalWars 3D Engine I built, I used the following code to achieve Late-Binding;
// 12/31/2009
///
/// Allows LateBinding some Assembly (dll) file, and then will
/// instantiate the given 'ClassName', and return the object to the caller.
/// ///
AssemblyFile name to load
///
Class Name to instantiate within Assembly
///
(OUT) Instantiated object
///
True/False of success private bool LateBindAssembly(string assemblyFile, string className, out object instantiatedObject)
{
instantiatedObject = null;
try
{
// set platform location to load from.
#if XBOX360
const string platformType = "XBox360";
#else
const string platformType = "x86";
#endif
var a = Assembly.LoadFrom("0LateBinds/" + platformType + "/" + assemblyFile);
var mytypes = a.GetTypes();
//const BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static |
// BindingFlags.Instance);
// Search for Instance to instantiate from Assembly.
foreach (var t in mytypes)
{
//var mi = t.GetMethods(flags);
#if XBOX360
// locate class instance to instantiate.
if (t.Name == className)
{
instantiatedObject = Activator.CreateInstance(t);
((ICommonInitilization) instantiatedObject).CommonInitilization(this);
return true;
}
#else
// locate class instance to instantiate.
if (t.Name == className)
{
instantiatedObject = Activator.CreateInstance(t, this);
return true;
}
#endif
/*foreach (var m in mi)
{
m.Invoke(obj, null);
}*/
}
// Name not found
return false;
}
// 1/1/2010 - Capture the possibility of the DLL not being in the folder at all.
catch (FileNotFoundException) // PC throws this.
{
System.Console.WriteLine(@"DLL Component {0} not found. Therefore, this will be skipped for late binding.", assemblyFile);
return false;
}
catch(IOException) // XBOX throws this.
{
System.Console.WriteLine(@"DLL Component {0} not found. Therefore, this will be skipped for late binding.", assemblyFile);
return false;
}
#if !XBOX360
catch (ReflectionTypeLoadException err)
{
if (err.LoaderExceptions != null)
{
// List out each LoaderException error to console.
foreach (var loaderException in err.LoaderExceptions)
{
if (loaderException.Message != null)
System.Console.WriteLine(@"LoaderExceptions reflection error - {0}", loaderException.Message);
}
MessageBox.Show(
@"Late-Binding failed, due to a Loading Exception on the Interface! This usually occurs if you have an outdated interface; please update your interface for the assembly you are trying to late-bind.",
@"LateBind Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
System.Console.WriteLine(@"DLL Component {0} reflection error. Therefore, this will be skipped for late binding.", assemblyFile);
return false;
}
#endif
}
The important piece to recognize is the C# line of code instantiatedObject = Activator.CreateInstance(t, this); . This is the key to creating the Late-Binding component and using it in the runtime.
But now I ask you, if the original program is not aware of the code until runtime, how could you possibly use any Late-Bind object. Well, this is where Interfaces come into play, which means at a minimum, the original program needs to be aware of the interface. However, even with this limitation, this concept does provide benefits.
In my TemporalWars 3D game engine, I used the concept of Late-Binding to abstract or separate out certain sections of code base from the original program; for example, the AStar pathfinding component or the Minimap component. This allows the main engine to be used separately without knowledge of these components, other than their interfaces. Then just by dropping one of these Late-Bind components into a folder, the program will check for any components and then automatically bind and instantiate them at runtime. Immediately, the component becomes active and usable via the Interfaces.
You can download a copy of the Minimap Component at the following codeplex addresss =>
, which is late-bindable project.
Also, you can download a copy of the FREE framework for TemporalWars 3D Game Engine at =>