Archive for XNA

Of Choppers, Physics, and Challenge

After receiving some sage advice from Andy “The ZMan” Dunn, I posted up the prototype of a game that I am working on for play test on the XNA Creator’s Club site:
http://forums.xna.com/forums/t/49219.aspx

The game focuses on controlling a small 2d chopper through a maze. There are “fans” which push and pull the chopper into the walls which of course will make it more difficult to navigate.

I got the idea after my brother-in-law received a small indoor helicopter for christmas. We all had so much fun trying to carefully control it (as much as one can control those tiny copters) and even trying to land it strange places like the blade of a ceiling fan. I thought that it would be fun to play a game that required the same skill. I was able to fairly quickly make a simple prototype (even simpler than what I posted up for playtest) using the FlatRedBall engine’s built in acceleration and collision functions.

The prototype I posted up is quite rough around the edges as it is just a prototype; But the idea is to get the community’s feedback early, before you have invested a lot of blood, sweat, and tears into a game. If you wait until the end to get a playtest, you will be so invested in what you’ve been working on that you will resist they playtester’s feedback. I hope to get some good ideas about possible directions that I could take it in … and hopefully it will validate the direction that I’ve already got in my mind. But who knows, I might get an idea that I was not expecting. That’s the great thing about getting it in front of other people early.

We will see just how far along I can get before my Orlando Code Camp presentation, which incidentally, is about actually finishing a game (this game). I’ll definitely have more to post on this topic after the codecamp :-)

Comments

State of Multitouch with XNA

I’ve been very interested in multitouch every since I saw Johnny Lee’s awesome finger tracking videos. Specifically, multitouch as it relates to game development. With the impending release of windows 7 tablet PCs, I have hopes that it might open up new possibilities and markets for games on the windows platform. I’m planning on picking up a Dell SX2210 monitor to start playing with it.

I sought out to find out the state of multitouch. So far, I’m not too impressed. Here are two great references to get you started:

  • Multitouch Madness: Brian Peek posted the slides and source code to a presentation he gave on multitouch. I really wish I could have been there but the source code and slides are a great resource.
  • XNA And Windows 7 Multitouch: Great article that shows how to get a touch enabled xna window rendering in windows forms.

The thing that I walked away with is that the solutions that Microsoft seems to be proposing have pretty specific dependencies on windows forms, wpf, and silverlight.  All things that I would rather not really deal with when I am making an XNA game. I would really prefer not to have to resort to making and managing my own window. In addition to the APIs not even really being available; Brian’s slides mention that System.Windows.Input.Manipulations isn’t even redistributable yet until .NET 4.0 is released.

So I’m going to be looking into how one can take advantage of the built-in touch APIs without onerous dependencies on unreleased assemblies and hacking windows forms in the near future. Anyone have any tips on where to get started?

Comments

Scurvy.Test v1.2 Released

Quick on the heals of yesterday’s post, I’ve released v1.2 of Scurvy.Test. This is the first official release of the framework and improvements over the initial announcement are mainly centered around the status reporting of test pass/failure.  I also upgraded the solution to vs 2k8 and xnags 3.1.

Here’s the changelog if you’re interested:

  • Introduced TestStatusReporter to make reporting test status easier. DefaultReporter writes to the debug output, while the test console app implements a custom ConsoleReporter that writes it out to the stdout instead.
  • Added additional methods and overloads to the Assert class for more assert options and the ability to replace your own custom TestStatusReporter instance.
  • Added XBox version of Scurvy.Test assembly
  • Upgraded solution to visual studio 2008
  • now using SVN bindings instead of TFS Explorer
  • Upgraded sample xna project to GS 3.1
  • Added custom XNA test status reporter to sample project

Comments

ScurvyTest v.next under way

I finally had a chance to do some long planned work on ScurvyTest, my flexible unit testing framework that was design from the ground up to be friendly to XNA project unit testing.

Specifically, one of the drawbacks to the previous version was that unit test status was only communicated via an easy to miss write to the debug output.  This next release will improve that by introducing an official status reporting mechanism. You will be able to replace this reporting channel with your own implementation to let you integrate with any custom game or engine.

I’m also adding more methods which will be available to you on the Assert class, and fixing a few bugs that have been reported in the exit criteria feature.

Check out the latest change set if you’re curious as to the latest, otherwise you can wait for the official release here in the next weeks :-)

http://scurvytest.codeplex.com/SourceControl/list/changesets

Comments

Resource Pool in F#

Erik Schulz, who has written a bunch of articles on how to make XNA games with F# has ported the Resource Pool class I wrote about in F#. Cool!

type FPool<'a>(newRoutine, capacity : int) =
    let queue = Queue<'a> capacity

    member this.Count = queue.Count

    member this.New() =
        if queue.Count > 0 then queue.Dequeue() else newRoutine()

    member this.Return(item) =
        queue.Enqueue(item)

I’ve been toying around with F# recently, it’s good to see an example that you can easily compare and contrast with the C# version. Has anyone else tried out F#?

Comments

XNA Resource Pool

This is likely an old topic at this point, considering the XNA framework has been out for several years. However, I meant to follow up on the topic of Resource Pooling after I posted the presentation materials from my ONETUG presentation on XNA last February. This is a simple resource pool that you can use to mitigate memory allocation issues in the XNA framework.

The canonical example of where a pool is useful, is a game entity firing bullets.  If you simply create a new instance of a bullet each time you fire, you will soon run out of memory. To avoid allocating new memory each time, you can reuse bullets that have moved off-screen or have collided with something.  There are several implementations that have been posted online such as:

These are great, they definitely do the job.  However, they have a common issue in that they want to take on too much responsibility. In both cases, the resource pool acts as an array to hold all known instances in addition to being concerned with object construction logic.

I wanted a simple resource pool which provided the functionality of providing a “new” instance of an object when I needed one. So I created my own; The basic design is that there are only two methods: “New”, and “Return”.  The new method returns a new instance that is ready to use, while the return method adds a previously obtained object back into the pool.

using System;
using System.Collections.Generic;

namespace Scurvy
{
    public class Pool<T> where T : class, new()
    {
        private Queue<T> queue;
        private Action<T> newRoutine;

        public Pool(int capacity)
        {
            this.queue = new Queue<T>(capacity);
        }

        public Pool()
        {
            this.queue = new Queue<T>();
        }

        public Pool(Action<T> newRoutine)
            : this()
        {
            this.newRoutine = newRoutine;
        }

        public int Count { get { return this.queue.Count; } }

        public T New()
        {
            T item;

            item = queue.Count > 0 ? queue.Dequeue() : new T();
            if (this.newRoutine != null) this.newRoutine(item);

            return item;
        }

        public void Return(T item)
        {
            queue.Enqueue(item);
        }
    }
}

An interesting feature of this pool is that you can control the object initialization logic by providing a simple lambda to the constructor. Any initialization logic (such as resetting “isdead” fields, or resetting positions) can be done there and it will be executed for each new instance.

I’d love to get feedback on this class if you end up using it in a project. Thanks!

Comments (2)

The Next Decade in Software

The scientists are already hard at work at coming up with predictions for the next 10 years. I thought it would be interesting to extract from the list, the predictions that are directly related to software … along with a few recommendations on how to get started today.

  • Augmented Reality
    This one is almost already a reality. A number of iPhone apps use the compass, gps, and camera as a viewport to overlay information on top of the world. A few years ago, Johnny Lee posted some amazing videos on how to use cheap consumer hardware to meld real and virtual worlds. It is clear that 3D graphics programming will be very helpful in this field … why not start learning now?
  • True artificially intelligent computer programs
    This one seems to be the most far fetched. Not because the field is not progressing, because it is, but because it’s been promised for so long. The biggest problem I think is lack of a clear goal; you can say you want something that learns, but learns what? There needs to be a catalyst that makes it clear what people really want/need from an intelligence. In my opinion, the game industry is pushing the state of the art here.
  • Cell phone apps that will act as a health monitor … Sort of an OnStar system for the body
    Since the iPhone proved to everyone that you can have a powerful computer in your pocket, new devices have started appearing that try to piggyback off of the success. I’m looking forward to more people making symbiotic peripherals for phones like the iphone, android based devices, and hopefully WinMo if they ever get their act together.  Mobile programming will surely be a skill to watch in the next decade.
  • Cloud computing
    I was a little surprised to see a reference to cloud computing in a science article. But it makes sense when you think about it, because scientists need to make increasingly complex models to prove their theories and solve problems, they will need more and more processing power to do it.

    I don’t think that it will be worth it for the average “you and me” to invest time into learning how to make cloud computing infrastructures. The big 3 (Microsoft, Google, and Amazon) will commoditize these infrastructures and make them easily available … for a price of course. Learning how to make programs that thrive in the clouds however, will prove to be useful. I’ve written some about this topic recently. You can start programming in functional languages like F#, or learn how to program shaders using HLSL to teach your brain how to think in highly parallelizable terms.

Time is always the ultimate author of history, so we will have to wait and see how many of these predictions turn out to be true.  But one thing is clear, if you learn how to make games, there is a good chance you will be successful in the next decade ;-)

Comments (1)

ONETUG XNA Presentation Files

As promised, here are the presentation files from the ONETUG presentation the other night.

http://codecube.net/bloguploads/ONETUG_XNA_20090129.zip

The .zip contains both the powerpoint slides that I used in the presentation, and the two sample projects I developed during the presentation.

  • TwoD
    • This sample shows some basic 2D techniques for dealing with sprites on the screen.
    • Simple velocity calculations for locomotion (Position += Velocity)
    • Orbiting one sprite around another
    • Launching projectiles at a steady pace.
    • Sprite helper class that makes it easy to position sprites around the world.
    • I didn’t use it in the sample, but I also have a ResourcePool datatype that makes it easy to reuse entities without having to reallocate new memory.  This is actually a really useful technique, I’d like to write about it in a separate blog post.
  • ThreeD
    • First Person Shooter style Camera.  It’s a GameComponent, so you just have to add it to the Components collection to use it.
    • Used the QuadDrawer class from the 3D Audio sample.  I added a few useful overloads and methods to let you draw billboarded sprites and the floor.
    • ModelSprite that makes drawing sprites and positioning it about the world easy.
    • Used the Sky box processor from the Generated Geometry sample.
    • All the helper classes (QuadDrawer, ModelSprite, and Sky) all know the camera, so they can make use of its view and projection matrix.

Thanks to everyone who showed up :-)

Comments

Using the LateBinder

Heh, I seemed to have not realized that I didn’t include any usage information on the LateBinder in the last post.  So here is the how and why you’d want to use this class.

Say you have a need to dynamically get or set the property of some class using the string name of the property.  Normally, the answer would be to use reflection, get the PropertyInfo, extract the MethodInfo of the getter or setter, and then invoke that method using the reflection API.  Hardly very usable … and if you’re not careful, you will end up paying the reflection cost everytime because you have to keep looking up the PropertyInfo and all that.

Enter the LateBinder<T> … using this class, you can do:

MyClass mcInstance = new MyClass();

LateBinder<MyClass> binder = LateBinder<MyClass>.Instance;
binder[mcInstance, "Name"] = “my name”;
string name = (string)binder[mcInstance, "Name"];

The late binder (on windows) uses the System.Reflection.Emit API to generate a DynamicMethod, which is much faster to call than the reflection invoke because it’s pre-compiled using custom built IL instructions.  It also caches them in the late binder instance so that it only has to be compiled once … and furthermore, if you use the singleton .Instance method, you only have to do the compilation once per application run since it keeps the data around in a static variable.

Beneath the hood, the original version of the late binder was using this class.  But I had to change the design of the class to support the cross platform aspect of it and to add in the static support.  It was pretty fun, I ended up using reflector to decompile some sample code I wrote in a console app so I could see what IL instructions I had to use to get/set the statics … so with this version of LateBinder, it supports getting and setting both properties and fields … regardless of whether they are instance or static fields/properties.

Now, on XBox and Zune, the story changes a bit because System.Reflection.Emit does not exist.  So, in this new version I posted, it falls back to simply using reflection.  However, it does keep the propertyinfo in that static cache, so at least you won’t have to pay the penalty of looking for it every time.

So to get back to the original question on usage (ie. when/why would I want to use it) … it probably wouldn’t be a good idea to use this in a tight loop in runtime code.  However, for certain tools and custom serialization code … it could certainly be very useful.  For example, you can relatively easily write code using this that will transfer property values from one class to another … assuming the property names are the same.  The list goes on and on as to how this is useful.

Comments (2)

New LateBinder

A long time ago, I posted a class called LateBinder to this site (the previous blog software).  I went on to use it rather prodigiously at work, and it also turned out to be a boon to others who visited this site (for example, Victor of FlatRedBall fame).  Unfortunately, it did have a few limitations; namely that it didn’t support getting/setting static fields and properties, and it also didn’t work on the xbox360 and zune because the System.Reflection.Emit namespace wasn’t available.

He asked me the other day the feasibility of supporting the static properties, and after a few days of hacking about, I’ve added that, and then some :-)

The version (below) not only supports static fields and properties, but it also supports the xbox360 and zune platforms.  Be warned though, I had to fall back on using simple reflection on the non-windows platforms … so the perf will obviously be slightly slower. 

I am fairly proud of how I was able to refactor the code to encapsulate the cross-platform differences.  If you look at the LateBindFactory abstract class, it uses a factory method to instantiate the platform-specific version.  This way, I was able to keep the pre-processor directives to a minimum, using them only where I needed … and also keeping the same public API for both platforms.

Let me know if this is useful for you  :-)

#region Using Statements

#if !XBOX360 && !ZUNE
#define USE_EMIT
#endif

using System;
using System.Collections.Generic;
using System.Reflection;
#if USE_EMIT
using System.Reflection.Emit;
#endif

#endregion

namespace Scurvy
{
    /// <summary>
    /// Provides a simple interface to late bind a class.
    /// </summary>
    /// <remarks>The first time you attempt to get or set a property, it will dynamically generate the get and/or set
    /// methods and cache them internally.  Subsequent gets uses the dynamic methods without having to query the type’s
    /// meta data.</remarks>
    public sealed class LateBinder<T>
    {
        #region Fields

        private static LateBindFactory factory = LateBindFactory.Create();
        private BindingFlags propertyFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
        private Type mType;
        private Dictionary<string, GetHandler> mPropertyGet;
        private Dictionary<string, SetHandler> mPropertySet;

        private Dictionary<Type, List<string>> mFields;

        private T mTarget = default(T);

        private static LateBinder<T> _instance;

        #endregion

        #region Properties

        public static LateBinder<T> Instance
        {
            get { return _instance; }
        }

        /// <summary>
        /// The instance that this binder operates on by default
        /// </summary>
        /// <remarks>This can be overridden by the caller explicitly passing a target to the indexer</remarks>
        public T Target
        {
            get { return mTarget; }
            set { mTarget = value; }
        }

        /// <summary>
        /// Gets or Sets the supplied property on the contained <seealso cref=”Instance”/>
        /// </summary>
        /// <exception cref=”InvalidOperationException”>Throws if the contained Instance is null.</exception>
        public object this[string propertyName]
        {
            get
            {
                //ValidateInstance();
                return this[mTarget, propertyName];
            }
            set
            {
                //ValidateInstance();
                this[mTarget, propertyName] = value;
            }
        }

        /// <summary>
        /// Gets or Sets the supplied property on the supplied target
        /// </summary>
        public object this[T target, string propertyName]
        {
            get
            {
                ValidateGetter(ref propertyName);
                return mPropertyGet[propertyName](target);
            }
            set
            {
                ValidateSetter(ref propertyName);
                mPropertySet[propertyName](target, value);
            }
        }

        #endregion

        #region Methods

        #region Constructors

        static LateBinder()
        {
            _instance = new LateBinder<T>();
        }

        public LateBinder(T instance)
            : this()
        {
            mTarget = instance;
        }

        public LateBinder()
        {
            mType = typeof(T);
            mPropertyGet = new Dictionary<string, GetHandler>();
            mPropertySet = new Dictionary<string, SetHandler>();

            mFields = new Dictionary<Type, List<string>>();
        }
        #endregion

        #endregion

        #region Public Accessors

        /// <summary>
        /// Sets the supplied property on the supplied target
        /// </summary>
        /// <typeparam name=”K”>the type of the value</typeparam>
        public void SetProperty<K>(T target, string propertyName, K value)
        {
#if !USE_EMIT

            // find out if this is a property or field
            Type type = typeof(T);

            PropertyInfo propertyInfo = type.GetProperty(propertyName);

            if (propertyInfo != null)
            {
                propertyInfo.SetValue(target, value, null);
            }

            else
            {
                FieldInfo fieldInfo = type.GetField(propertyName);

                if (fieldInfo != null)
                {
                    fieldInfo.SetValue(target, value);
                }
                else
                {
                    throw new ArgumentException(“Cannot find property or field with the name ” + propertyName);
                }

            }

#else
            ValidateSetter(ref propertyName);

            if (mPropertySet.ContainsKey(propertyName))
            {
                mPropertySet[propertyName](target, value);
            }
            else
            {
                // This is probably not a property so see if it is a field.

                FieldInfo fieldInfo = mType.GetField(propertyName);

                if (fieldInfo == null)
                {
                    string errorMessage =
                        “LateBinder could not find a field or property by the name of ” + propertyName +
                        “Check the name of the property to verify if it is correct.”;
                    throw new System.MemberAccessException(errorMessage);
                }
                else
                {
                    object[] args = { value };
                    mType.InvokeMember(propertyName, BindingFlags.SetField, null, target, args);
                }
            }
#endif
        }

        public object GetField(T target, ref string propertyName)
        {
            Binder binder = null;
            object[] args = null;

            return mType.InvokeMember(
               propertyName,
               BindingFlags.GetField,
               binder,
               target,
               args
               );
        }

        /// <summary>
        /// Gets  the supplied property on the supplied target
        /// </summary>
        /// <typeparam name=”K”>The type of the property being returned</typeparam>
        public K GetProperty<K>(T target, ref string propertyName)
        {
            ValidateGetter(ref propertyName);
            return (K)mPropertyGet[propertyName](target);
        }

        public object GetProperty(T target, ref string propertyName)
        {
            ValidateGetter(ref propertyName);
            return mPropertyGet[propertyName](target);
        }

        #endregion

        #region Private Helpers

        private void ValidateInstance()
        {
            if (mTarget == null)
            {
                throw new InvalidOperationException(“Instance property must not be null”);
            }
        }

        private void ValidateSetter(ref string propertyName)
        {
            if (!mPropertySet.ContainsKey(propertyName))
            {
                PropertyInfo propertyInfo = mType.GetProperty(propertyName, this.propertyFlags);

                if (propertyInfo != null)
                {
                    mPropertySet.Add(propertyName, factory.CreateSetHandler(mType, propertyInfo));
                }
            }
        }

        private void ValidateGetter(ref string propertyName)
        {
            if (!mPropertyGet.ContainsKey(propertyName))
            {
                mPropertyGet.Add(propertyName, factory.CreateGetHandler(mType, mType.GetProperty(propertyName)));
            }
        }

        #endregion

        #region Contained Classes

        internal delegate object GetHandler(object source);
        internal delegate void SetHandler(object source, object value);
        internal delegate object InstantiateObjectHandler();

        internal abstract class LateBindFactory
        {
            public LateBindFactory()
            {
            }

            public static LateBindFactory Create()
            {
#if USE_EMIT
                return new DynamicMethodFactory();
#else
                return new ReflectionFactory();
#endif
            }

            public abstract InstantiateObjectHandler CreateInstantiateObjectHandler(Type type);
            public abstract GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo);
            public abstract GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo);
            public abstract SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo);
            public abstract SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo);
        }

#if USE_EMIT
        internal sealed class DynamicMethodFactory : LateBindFactory
        {
            public DynamicMethodFactory()
            {
            }

            #region Public Methods

            public override InstantiateObjectHandler CreateInstantiateObjectHandler(Type type)
            {
                ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
                if (constructorInfo == null)
                {
                    throw new ApplicationException(string.Format(“The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).”, type));
                }

                DynamicMethod dynamicMethod = new DynamicMethod(“InstantiateObject”, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, type, true);
                ILGenerator generator = dynamicMethod.GetILGenerator();
                generator.Emit(OpCodes.Newobj, constructorInfo);
                generator.Emit(OpCodes.Ret);
                return (InstantiateObjectHandler)dynamicMethod.CreateDelegate(typeof(InstantiateObjectHandler));
            }

            public override GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo getMethodInfo = propertyInfo.GetGetMethod(true);

                DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
                ILGenerator getGenerator = dynamicGet.GetILGenerator();

                if (!getMethodInfo.IsStatic)
                {
                    getGenerator.Emit(OpCodes.Ldarg_0);
                }
                getGenerator.Emit(OpCodes.Call, getMethodInfo);
                BoxIfNeeded(getMethodInfo.ReturnType, getGenerator);
                getGenerator.Emit(OpCodes.Ret);

                return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
            }

            public override GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo)
            {

                DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
                ILGenerator getGenerator = dynamicGet.GetILGenerator();

                if (!fieldInfo.IsStatic)
                {
                    getGenerator.Emit(OpCodes.Ldarg_0);
                }
                getGenerator.Emit(OpCodes.Ldfld, fieldInfo);
                BoxIfNeeded(fieldInfo.FieldType, getGenerator);
                getGenerator.Emit(OpCodes.Ret);

                return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
            }

            public override SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo setMethodInfo = propertyInfo.GetSetMethod(true);

                DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
                ILGenerator setGenerator = dynamicSet.GetILGenerator();

                if (!setMethodInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Ldarg_0);
                }
                setGenerator.Emit(OpCodes.Ldarg_1);
                UnboxIfNeeded(setMethodInfo.GetParameters()[0].ParameterType, setGenerator);
                setGenerator.Emit(OpCodes.Call, setMethodInfo);
                setGenerator.Emit(OpCodes.Ret);

                return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
            }

            public override SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo)
            {
                DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
                ILGenerator setGenerator = dynamicSet.GetILGenerator();

                if (!fieldInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Ldarg_0);
                }
                setGenerator.Emit(OpCodes.Ldarg_1);
                UnboxIfNeeded(fieldInfo.FieldType, setGenerator);

                if (!fieldInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Stfld, fieldInfo);
                }
                else
                {
                    setGenerator.Emit(OpCodes.Stsfld, fieldInfo);
                }

                setGenerator.Emit(OpCodes.Ret);

                return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
            }

            #endregion

            #region Private Methods

            private static DynamicMethod CreateGetDynamicMethod(Type type)
            {
                return new DynamicMethod(“DynamicGet”, typeof(object), new Type[] { typeof(object) }, type, true);
            }

            // CreateSetDynamicMethod
            private static DynamicMethod CreateSetDynamicMethod(Type type)
            {
                return new DynamicMethod(“DynamicSet”, typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
            }

            // BoxIfNeeded
            private static void BoxIfNeeded(Type type, ILGenerator generator)
            {
                if (type.IsValueType)
                {
                    generator.Emit(OpCodes.Box, type);
                }
            }

            // UnboxIfNeeded
            private static void UnboxIfNeeded(Type type, ILGenerator generator)
            {
                if (type.IsValueType)
                {
                    generator.Emit(OpCodes.Unbox_Any, type);
                }
            }

            #endregion
        }
#endif

#if !USE_EMIT
        internal sealed class ReflectionFactory : LateBindFactory
        {
            public ReflectionFactory()
            {
            }

            public override InstantiateObjectHandler CreateInstantiateObjectHandler(Type type)
            {
                return delegate()
                {
                    return Activator.CreateInstance(type);
                };
            }

            public override GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo method = propertyInfo.GetGetMethod(true);

                return delegate(object source)
                {
                    return method.Invoke(method.IsStatic ? null : source, null);
                };
            }

            public override GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo)
            {
                return delegate(object source)
                {
                    return fieldInfo.GetValue(fieldInfo.IsStatic ? null : source);
                };
            }

            public override SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo method = propertyInfo.GetSetMethod();

                return delegate(object source, object value)
                {
                    method.Invoke(method.IsStatic ? null : source, new object[] { value });
                };
            }

            public override SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo)
            {
                return delegate(object source, object value)
                {
                    fieldInfo.SetValue(fieldInfo.IsStatic ? null : source, value);
                };
            }
        }
#endif
        #endregion
    }
}

Comments