Skip to main content
GameDev.net gamedev.net
🔒 Locked

Scripting A C# Object

Started by dave Apr 10, 2010 at 7:55 AM 1 replies 900+ views
Original Post
dave
dave
This sounds like a bit of a stretch, but what i would like to do is have a text file that scripts the properties of an entity:

Player:
  Float:Health
  Float:Ammo
Such that the object can be edited in a PropertyGrid. Can anyone suggest an elegant way of doing this, if it's possible at all. Thanks, EDIT: Thinking about it some more, if i could populate a property grid from an ArrayList of differently typed objects, then i can just parse this script file into an ArrayList quite easily.
benryves
benryves
The way I've done this in the past is to use reflection to create a new type at runtime using reflection, create an instance of it and point the PropertyGrid at it.

public static class DynamicPropertyBag {    public class Property {        public string Name { get; set; }        public Type Type { get; set; }    }    public static Type Create(IEnumerable<Property> properties) {        var aName = new AssemblyName("DynamicPropertyBagAssembly");        AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);        ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);        TypeBuilder tb = mb.DefineType("DynamicPropertyBag", TypeAttributes.Public);        foreach (var property in properties) {            FieldBuilder backingStore = tb.DefineField("m_" + property.Name, property.Type, FieldAttributes.Private);            PropertyBuilder pbNumber = tb.DefineProperty(property.Name, PropertyAttributes.None, property.Type, null);            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;            // Getter.            MethodBuilder mbNumberGetAccessor = tb.DefineMethod("get_" + property.Name, getSetAttr, property.Type, Type.EmptyTypes);            ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();            numberGetIL.Emit(OpCodes.Ldarg_0);            numberGetIL.Emit(OpCodes.Ldfld, backingStore);            numberGetIL.Emit(OpCodes.Ret);            // Setter.            MethodBuilder mbNumberSetAccessor = tb.DefineMethod("set_" + property.Name, getSetAttr, null, new Type[] { property.Type });            ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator();            numberSetIL.Emit(OpCodes.Ldarg_0);            numberSetIL.Emit(OpCodes.Ldarg_1);            numberSetIL.Emit(OpCodes.Stfld, backingStore);            numberSetIL.Emit(OpCodes.Ret);            // Last, map the "get" and "set" accessor methods to the PropertyBuilder. The property is now complete.             pbNumber.SetGetMethod(mbNumberGetAccessor);            pbNumber.SetSetMethod(mbNumberSetAccessor);        }        // Finish the type.        return tb.CreateType();    }}


As an example of its usage:
// Create a player type (in your case, from properties defined in a file).var playerType = DynamicPropertyBag.Create(new[] {     new DynamicPropertyBag.Property {        Name = "Health",        Type = typeof(float),    },    new DynamicPropertyBag.Property {        Name = "Ammo",        Type = typeof(float),    },});// Create an instance of the player.var player = Activator.CreateInstance(playerType);// Set a property.playerType.InvokeMember("Health", BindingFlags.SetProperty, null, player, new object[] { 100.0f });// Retrieve a property.var playerAmmo = (float)playerType.InvokeMember("Ammo", BindingFlags.GetProperty, null, player, null);
[Website] [+++ Divide By Cucumber Error. Please Reinstall Universe And Reboot +++]
ernow
ernow
And after next week have a look at .NET and C# 4 so you could replace a the cool reflection code with dynamic objects.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.