xboxscene.org forums

Author Topic: Using “late-binding” In Xna 4.0 And The Importance Of Interfaces  (Read 970 times)

berben11

  • Archived User
  • Newbie
  • *
  • Posts: 2

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, let’s talk about ‘Late-Binding’ first and connect how Interfaces become useful in this situation.

IPB Image

“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 didn’t 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”;

CODE

// 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 => Minmap at Codeplex, which is late-bindable project.
        Also, you can download a copy of the FREE framework for TemporalWars 3D Game Engine at => Temporalwars.com
Logged