Creating an ORM in C# - Part 2

This is another long one, but hopefully it wont completely bore you... So I’m a bit further now with the ORM. It’s currently to the point where I’m creating classes, overriding properties, etc. And I’ve already run into bugs with the code that I’ve posted thus far. As such I have gone back for some fixes. Specifically I didn’t realize that the expression tree would actually contain a node to convert the object from one type to an object type. But that’s an easy fix. Past that I’ve also settled on a name for this thing, HaterAide. I chose this because everyone seems to talk about “hydrating” their objects, I hate dealing with data layers, and I saw one of the new “G” commercials when I was thinking up a name. Plus, everything else I thought up was taken.

Anyway, let’s move on to some code (I’m going to post the current source code later in the post). Last time we talked about using reflection and expression trees in order to get information about the properties within a class and map them within our system. This time we’re adding 3 more mapping types and talking about how to use Reflection.Emit in order to create classes that override properties.

So let’s start with the mappings. In the last post, I created an ID and Reference mapping type. ID would be the ID of the object (note that I didn’t make it unique as I want to allow composite IDs). Reference on the other hand deals with simple types (string, int, etc. in either a list or a single value). This time we’re adding Map, ManyToOne, and ManyToMany to the ClassMapping class. Map deals with situations where it is a one to one mapping of another business object. So let’s look at its code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using HaterAide.Interfaces;

namespace HaterAide
{
    public class ClassMapping<T> : IClassMap<T>, IAttributeMap
    {
        private void AddAttribute(Attribute Property, Expression<Func<T, object>> expression)
        {
            string[] SplitName = null;
            if (expression.Body.NodeType == ExpressionType.Convert)
            {
                Property.Name = expression.Body.ToString().Replace("Convert(", "").Replace(")", "");
                string[] Splitter = { "." };
                SplitName = Property.Name.Split(Splitter, StringSplitOptions.None);
                Property.Name = SplitName[SplitName.Length - 1];
                UnaryExpression TempUnary = (UnaryExpression)expression.Body;
                Property.Type = TempUnary.Operand.Type;
            }
            else
            {
                Property.Name = expression.Body.ToString();
                string[] Splitter = { "." };
                SplitName = Property.Name.Split(Splitter, StringSplitOptions.None);
                Property.Name = SplitName[SplitName.Length - 1];
                Property.Type = expression.Body.Type;
            }
            Properties.Add(Property);
        }

        #region IClassMap Members

        public void ID(Expression<Func<T, object>> expression)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.ID;
            AddAttribute(_ID, expression);
        }

        public void Reference(Expression<Func<T, object>> expression)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.Reference;
            AddAttribute(_ID, expression);
        }

        public void Map(Expression<Func<T, object>> expression, string MappedProperty, bool Cascade)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.Map;
            _ID.MappedProperty = MappedProperty;
            _ID.Cascade = Cascade;
            AddAttribute(_ID, expression);
        }

        public void ManyToOne(Expression<Func<T, object>> expression, string MappedProperty, bool Cascade)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.ManyToOne;
            _ID.MappedProperty = MappedProperty;
            _ID.Cascade = Cascade;
            AddAttribute(_ID, expression);
        }

        public void ManyToMany(Expression<Func<T, object>> expression, string MappedProperty, bool Cascade)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.ManyToMany;
            _ID.MappedProperty = MappedProperty;
            _ID.Cascade = Cascade;
            AddAttribute(_ID, expression);
        }

        #endregion

        #region IAttributeMap Members

        private List<Attribute> _Properties = new List<Attribute>();

        public List<Attribute> Properties
        {
            get { return _Properties; }
            set { _Properties = value; }
        }

        #endregion
    }
}

Map, as you can see above, contains two new values that need to be sent in. One is the MappedProperty variable.  It lets the system know what this object corresponds to on the other object. For instance if we have a class called Dog that contained a property called Owner (of type Person) and the Person class contained a property called MyDog (of type Dog), we need to know that those match up. So, on the Dog class we’d pass in “MyDog” for the MappedProperty variable. Note that if the other class doesn’t contain a property that maps back, we’d leave this null. The other variable is Cascade. This determines whether or not to cascade deletes, inserts, updates, etc. when this class is updated. ManyToOne and ManyToMany work in similar fashion, just changing the attribute type to the appropriate value.

That’s all there is to it really for adding those types. We still load the information the same way we just need extra information when it is created. The next portion that I want to show you is the use of Reflection.Emit.

For those of you that don’t know what the Reflection.Emit namespace is, it contains classes that let you spit out MSIL (Microsoft Intermediate language) code, metadata, etc. It’s usually only used if you’re creating something like a scripting engine. However in our case we’re going to use it to dynamically create classes that will use the business objects as base classes. In order to do this, we’re going to create 4 classes, a class manager (which looks through the assembly, finds the ClassMapping classes, and stores the created Class objects), a class to define/create the classes, a class to override properties, and a class to define fields. So let’s take a look at the ClassManager class first:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/

#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Reflection.Emit;
#endregion

namespace HaterAide.Reflection
{
    /// <summary>
    /// Class manager
    /// </summary>
    internal class ClassManager
    {
        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Assembly">Assembly Using</param>
        public ClassManager(Assembly Assembly)
        {
            CreateAssembly();
            LoadClasses(Assembly);
            foreach (Type Key in Classes.Keys)
            {
                object CreatedClass = Activator.CreateInstance(this[Key].DerivedType);
                PropertyInfo Info = this[Key].DerivedType.GetProperty("ID");
                Info.SetValue(CreatedClass, 1, null);
                this[Key].DerivedType.InvokeMember("ClearChanged0", BindingFlags.InvokeMethod, null, CreatedClass, null);
            }
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// Creates the assembly builder
        /// </summary>
        private void CreateAssembly()
        {
             AssemblyName Name=new AssemblyName("HaterAide0Classes");
            AppDomain Domain=Thread.GetDomain();
            Builder=Domain.DefineDynamicAssembly(Name, AssemblyBuilderAccess.Run);
            Module = Builder.DefineDynamicModule("HaterAide0ClassesM");
        }

        /// <summary>
        /// Loads the classes from the assembly and maps the business object type to
        /// the mapping class
        /// </summary>
        /// <param name="BusinessObjectsAssembly">Assembly containing the business objects</param>
        private void LoadClasses(Assembly BusinessObjectsAssembly)
        {
            Type[] Types=BusinessObjectsAssembly.GetTypes();
            foreach (Type TempType in Types)
            {
                Type BaseType = TempType.BaseType;
                if (BaseType != null && BaseType.FullName.StartsWith("HaterAide.ClassMapping"))
                {
                    Classes.Add(BaseType.GetGenericArguments()[0], new Class(TempType, Module));
                }
            }
        }

        #endregion

        #region Private Variables

        private Dictionary<Type, Reflection.Class> Classes = new Dictionary<Type, HaterAide.Reflection.Class>();
        private AssemblyBuilder Builder=null;
        private ModuleBuilder Module=null;

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the associated class with the type
        /// </summary>
        /// <param name="value">Type value</param>
        /// <returns>The generated class associated</returns>
        public Reflection.Class this[Type value]
        {
            get
            {
                return Classes[value];
            }
        }

        #endregion
    }
}

The ClassManager class was shown last time but you’ll notice a number of changes. It still takes an assembly as input, but it adds a function (CreateAssembly). CreateAssembly is our first glimpse of Reflection.Emit. Within the function, we create an AssemblyName object, an AssemblyBuilder object, and a ModuleBuilder object. The AssemblyName object simply defines the assembly’s name that the generated objects will reside within. The AssemblyBuilder is used to actually create the assembly and the ModuleBuilder is what we will be using to define the module (pretty straightforward considering their names). These objects have to be created prior to anything else, but really the only object that we’re going to care about past this is the ModuleBuilder object.

The LoadClasses function looks fairly similar to the past version, but this time we’re sending in the ModuleBuilder to the class object. That’s really the only changes to the ClassManager class. The Class class though has a number of changes:

/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/

#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using HaterAide.Interfaces;
#endregion

namespace HaterAide.Reflection
{
    /// <summary>
    /// Used to override a class
    /// </summary>
    internal class Class
    {
        public Class(Type Class, ModuleBuilder Module)
        {
            Type BaseType = Class.BaseType;
            Type GenericType = BaseType.GetGenericArguments()[0];
            TypeBuilder TypeBuilder = Module.DefineType("HaterAide0ClassesM." + GenericType.Name + "Derived", TypeAttributes.Public, GenericType);
            FieldBuilder ChangedField = CreateChangedFields(TypeBuilder);
            CreateChangedClearMethod(TypeBuilder, ChangedField);
            CreateConstructor(ChangedField, TypeBuilder, GenericType);
            OverrideProperties(ChangedField, TypeBuilder, Class);

            _DerivedType = TypeBuilder.CreateType();
        }

        private void CreateChangedClearMethod(TypeBuilder TypeBuilder, FieldBuilder ChangedField)
        {
            MethodBuilder Method = TypeBuilder.DefineMethod("ClearChanged0", MethodAttributes.Public, typeof(void), new Type[0]);
            ILGenerator Generator = Method.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, ChangedField);
            Generator.Emit(OpCodes.Callvirt, typeof(List<string>).GetMethod("Clear"));
            Generator.Emit(OpCodes.Ret);
        }

        private void OverrideProperties(FieldBuilder ChangedField, TypeBuilder TypeBuilder, Type ClassMapper)
        {
            IAttributeMap Item = (IAttributeMap)Activator.CreateInstance(ClassMapper);
            foreach (Attribute Property in Item.Properties)
            {
                if (Property.AttributeType == AttributeType.ID || Property.AttributeType == AttributeType.Reference)
                {
                    Properties.Add(new Property(Property, TypeBuilder, ChangedField));
                }
            }
        }

        private FieldBuilder CreateChangedFields(TypeBuilder TypeBuilder)
        {
            FieldBuilder ValueField = TypeBuilder.DefineField("_ChangedList0", typeof(List<string>), FieldAttributes.Private);
            PropertyBuilder Property = TypeBuilder.DefineProperty("ChangedList0", PropertyAttributes.None, typeof(List<string>), null);

            MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

            MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_ChangedList0", GetSetAttributes, typeof(List<string>), Type.EmptyTypes);
            ILGenerator Generator = ValuePropertyGet.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, ValueField);
            Generator.Emit(OpCodes.Ret);

            MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_ChangedList0", GetSetAttributes, null, new Type[] { typeof(List<string>) });
            Generator = ValuePropertySet.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldarg_1);
            Generator.Emit(OpCodes.Stfld, ValueField);
            Generator.Emit(OpCodes.Ret);

            Property.SetGetMethod(ValuePropertyGet);
            Property.SetSetMethod(ValuePropertySet);

            return ValueField;
        }

        private void CreateConstructor(FieldBuilder ChangedField, TypeBuilder TypeBuilder,Type GenericType)
        {
            ConstructorBuilder Constructor = TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]);
            ILGenerator Generator = Constructor.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Call, GenericType.GetConstructor(new Type[0]));
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Newobj, typeof(List<string>).GetConstructor(new Type[0]));
            Generator.Emit(OpCodes.Stfld, ChangedField);
            Generator.Emit(OpCodes.Ret);
        }

        private List<Property> _Properties = new List<Property>();

        private Type _DerivedType = null;

        public Type DerivedType
        {
            get { return _DerivedType; }
        }

        public List<Property> Properties
        {
            get { return _Properties; }
        }
    }
}

You’ll notice that the constructor has a couple of new functions and it creates a TypeBuilder object. The TypeBuilder is the class that actually defines the class. In our case we want a public class that derives from the business object (the GenericType object is the business object type). After the type is initially defined, it isn’t created. We still have to define constructors, functions, etc. prior to calling the CreateType function.

Before we do anything, we need to define a Changed field, which will tell us if a property is assigned to (this is done in the CreateChangedFields function).  When defining your class, you can create Fields, Properties, and Methods (there are other things but that’s what we care about). In the CreateChangedFields function, we start by creating a field (private list of strings to hold our list of changed variables). We also define a property and then have to define the properties get and set methods. Note that these methods (when defined by the compiler) will almost always start with get_ or set_ and then end with the name of the property. Anyway, within the get/set methods we get our first glimpse of op codes and IL generation.

IL is really nothing more than a series of op codes. Each op code does something (except of course nop). These op codes are generated by something called an ILGenerator. Every time you call Emit, you feed it an op code and the needed variables. In the ChangedList0 property all we’re doing is setting/getting the list. So in our get function, we start with the Ldarg_0 op code. This op code loads whatever is at index 0 (usually it’s the this variable). We then call Ldfld and feed in our field that we created. Ldfld simply loads a field and puts it on the evaluation stack. We then call Ret. Ret simply takes whatever is on top of the evaluation stack and returns it (in our case the field).

Now before you get worried about having to go and figure out every op code that you’ll need for a function, there’s a way to get that information from the system itself. First create a project, create a function/class/property that does the action that you want it to do. Then call ILDasm. ILDasm can be found here: C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ildasm.exe. You can even set it up to run from within Visual Studio. Simply create an external tool entry that takes the location of ILDasm as the command and “$(TargetPath)” as the arguments. That’s all there is to it. So no worries on creating functions with Reflection.Emit, it’s actually quite easy.

Anyway, the next function that is called is CreateChangedClearMethod. This just allows the system to clear the changed list. Next is the constructor. The reason that isn’t created first is the fact that we have to actually create the changed list. The field, when defined, will default to null. So we need to set it in the constructor and as such we need to define the field first before we can instantiate it. The constructor first calls the base class’s (our business object’s) constructor, then creates a new list of strings, and finally stores it in the changed list field.

After the constructor we move on to the individual properties. We simply create an instance of the ClassMap and pull down the information about the properties. We then create Property objects and store them for later. The Property class is here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using HaterAide.Interfaces;
using System.Reflection;

namespace HaterAide.Reflection
{
    internal class Property
    {
        public Property()
        {
        }

        public Property(Attribute Attribute, TypeBuilder TypeBuilder, FieldBuilder ChangedField)
        {
            Field = new Field(Attribute, TypeBuilder);
            MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
            MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_" + Attribute.Name, GetSetAttributes, Attribute.Type, Type.EmptyTypes);
            ILGenerator Generator = ValuePropertyGet.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, Field.FieldBuilder);
            Generator.Emit(OpCodes.Ret);


            MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_" + Attribute.Name, GetSetAttributes, null, new Type[] { Attribute.Type });

            Generator = ValuePropertySet.GetILGenerator();

            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldarg_1);
            Generator.Emit(OpCodes.Stfld, Field.FieldBuilder);
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, ChangedField);
            Generator.Emit(OpCodes.Ldstr, Attribute.Name);
            Generator.Emit(OpCodes.Callvirt, typeof(List<string>).GetMethod("Add"));
            Generator.Emit(OpCodes.Ret);

            _Attribute = Attribute;
        }

        private Field Field = null;

        private Attribute _Attribute;

        public Attribute Attribute
        {
            get { return _Attribute; }
            set { _Attribute = value; }
        }
    }
}

This one is similar to the Class object in that we’re using ILGenerator to define methods. You will notice one change though. Namely we aren’t defining a property. I talked about this issue before, but when you’re overriding a property, you’re really only overriding the get/set methods. Creating a property with the same name would cause the app to think that there were two properties with the same name, confuse it, and crash our program. Not what we want. Past that, everything should look familiar (with the exception of some op codes that were not used previously). One thing that may be tricky at first can be found in the set function. After storing the information in the field (which is actually created by the Field class) for the property, it goes on to call the Add function on the changed list. It starts off by loading the this variable, then the field, then the name of the property, prior to calling Add. The this variable has to be loaded first because otherwise it does not know from which object the field should be taken from. If it were a local variable, we wouldn’t have to worry about it but it’s a field so you have to load this first. That annoyed the heck out of me the first time that bug popped up.

And that’s all there is to the Reflection portion of the ORM. We now have our classes, they can be created. We can save/get information from them (assuming we had the SQL portion set up). There are a couple minor changes/additions that will need to be added but since I’m going for something basic I’m happy. So download the code, leave feedback, and happy coding.

HaterAidePart2.zip (332.92 kb)

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/13/2009 at 10:27 AM
Tags: , , ,
Categories: C#
Post Information: Permalink | Comments (1) | Post RSSRSS comment feed

Creating an ORM in C# - Part 1

Just as a warning, this is a long post. And before you groan and start running for the hills because someone mentioned building ANOTHER ORM (as if we need another one), note that this isn't meant to be something you would use in your own project. I've been working on this in my spare time as a side project to learn various features of C# 3.0 and .Net that I've never really gotten into before. And since this is a learning exercise, I decided to share my adventure with everyone else that's out there. Also keep in mind that this is not the best way to create an ORM. I'm certain that people who have successfully created one will read this and laugh at my poor attempt, but once again this is for learning purposes... Also, if you don't know what an ORM is, read this.

Anyway, I might as well tell you my motivation. I mean I could pick any project under the sun to learn some of these concepts, classes, etc. in the framework. So why did I pick an ORM? The main reason was that I've yet to find an ORM that works the way that I want it to. NHibernate is close (and I do like the Fluent version), but it's still not quite what I want. That's it really. I just want something where I don't have to design my objects around it and it plugs in without too much of an issue (oh and no XML or Attributes littering my business objects).

Anyway, I’ve divided the ORM into four sections that I’ll need to create:

  1. Reflection – I need to figure out what properties exist in an object, etc. And like I said above, I don’t want to use attributes or XML. That leaves me using reflection and writing a couple classes to help get the information that I need and store it for later use.
  2. SQL Builder – This will actually create the tables, create the queries, etc. In this setup, I’m only dealing with SQL Server, but I’m going to build it using a provider model so that could be swapped out.
  3. Cache – To be honest, calling a database is a bit slow sometimes. So I need to create a mechanism to cache the information. I’m designing this only for web sites, but once again I’m going to try to build it in such a way that it could be swapped out.
  4. Settings – I need an easy way to configure this thing. So I need something simple to store that information.

 


So really it’s only 3 sections but I’m still going to count the settings… Anyway, in this post I’m going to talk about the reflection portion. And actually I’m not going to cover it completely in this post, just how to get the property information.

So I need some basic information from the properties of the business objects. Namely the name of the property, the base type, and the type of mapping that we want to use. So I’m using this class to hold that information

 


    public class Attribute
    {
        public Attribute()
        {
        }

        private string _Name = "";
        private Type _Type = null;
        private AttributeType _AttributeType = AttributeType.ID;

        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public Type Type
        {
            get { return _Type; }
            set { _Type = value; }
        }

        public AttributeType AttributeType
        {
            get { return _AttributeType; }
            set { _AttributeType = value; }
        }
    }

    public enum AttributeType
    {
        ID = 0,
        Reference
    }


Note that the attribute type defines only properties that are either the ID for the object or a reference (think simple types like string, int, etc. I’ll add in classes, many to many mappings later). But so far this is pretty basic. On top of this, I’m not hard coding the business objects nor am I forcing them to inherit from an interface/base class. So I need a class so they can define the mapping with:

    public interface IAttributeMap
    {
        List<Attribute> Properties { get; set; }
    }

    public interface IClassMap<T>
    {
        void ID(Expression<Func<T, object>> expression);
        void Reference(Expression<Func<T, object>> expression);
    }

    public class ClassMapping<T> : IClassMap<T>, IAttributeMap
    {
        private void AddAttribute(Attribute Property, Expression<Func<T, object>> expression)
        {
            Property.Name = expression.Body.ToString();
            string[] Splitter = { "." };
            string[] SplitName = Property.Name.Split(Splitter, StringSplitOptions.None);
            Property.Name = SplitName[SplitName.Length - 1];
            Property.Type = expression.Body.Type;
            Properties.Add(Property);
        }

        #region IClassMap Members

        public void ID(Expression<Func<T, object>> expression)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.ID;
            AddAttribute(_ID, expression);
        }

        public void Reference(Expression<Func<T, object>> expression)
        {
            Attribute _ID = new Attribute();
            _ID.AttributeType = AttributeType.Reference;
            AddAttribute(_ID, expression);
        }

        #endregion

        #region IAttributeMap Members

        private List<Attribute> _Properties = new List<Attribute>();

        public List<Attribute> Properties
        {
            get { return _Properties; }
            set { _Properties = value; }
        }

        #endregion
    }


Ok, now the code above contains something you may have not seen before. Namely the Expression<Func<T,object>> expression part. You see in C# 3.0, an operator was added called the lambda operator. The lambda operator is used to create lambda expressions. Lambda expressions are anonymous functions that can contain statements, etc. and can be used to create expression trees or delegates. The portion of that, that we care about is expression trees.

An expression tree, which was introduced along with Linq, allows for translating executable code into data allowing us to modify the code before executing it... To be honest, that doesn’t sound all that useful but it means that we can do things like this:


X=>X.PropertyName


And the property’s information (such as name, type, etc.) would be available to us. And that’s what we need, so that’s what we’re using. So how do we use the ClassMapping class?


    public class MyClassMap : ClassMapping<MyClass>
    {
        public MyClassMap()
        {
            ID(x => x.ID);
            Reference(x => x.TestProperty);
        }
    }

    public class MyClass
    {
        public MyClass()
        {
        }

        public virtual int ID { get; set; }

        public virtual string TestProperty { get; set; }
    }


The code above will look familiar to you if you’ve used Fluent NHibernate (I'm using their technique for defining the mappings). But the business object is MyClass. MyClassMap is the mapping class and inherits from ClassMapping. The reason we made ClassMapping generic was so we could do this. You’ll notice that both the ID and Reference functions take in T type as the first portion. This allows us to define an object of the type that we define (in the example above, MyClass), and call its properties (which will end up in the body portion of the expression and we can get our information from there).

So we have our very basic mapping, we have classes to pull and hold the information that we need so now we just need something to find all of our mappings.


    internal class ClassManager
    {
        #region Constructor

        public ClassManager(Assembly Assembly)
        {
            LoadClasses(Assembly);
        }

        #endregion

        #region Private Functions

        private void LoadClasses(Assembly BusinessObjectsAssembly)
        {
            Type[] Types=BusinessObjectsAssembly.GetTypes();
            foreach (Type TempType in Types)
            {
                Type BaseType = TempType.BaseType;
                if (BaseType != null && BaseType.FullName.StartsWith("ClassMapping"))
                {
                    Classes.Add(BaseType.GetGenericArguments()[0], new Class(TempType));
                }
            }
        }

        #endregion

        #region Private Variables

        private Dictionary<Type, Class> Classes = new Dictionary<Type, Class>();

        #endregion
    }

    internal class Class
    {

        public Class(Type ClassMapping)
        {
            IAttributeMap Item = (IAttributeMap)Activator.CreateInstance(ClassMapping);
            foreach (Attribute Property in Item.Properties)
            {
                //Here is where we’ll add our property overridding at a later time
            }
        }
    }


So there you go. Our ClassManager class uses reflection to find all classes that inherit from the ClassMapping class. In turn it creates a Class object (which will later override various properties and be used to create a derived type that we will use to actually store/load the information from the database). The Class object then creates an instance of the class mapping and can then get the information from it about the various properties.

So there’s the beginning of my ORM. I’m certain that flaws will be found and things will change but this is what I have at the moment (actually I’m a bit further than this, but this is what I’m going to share for now). So take a look, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/8/2009 at 10:01 AM
Tags: , , , ,
Categories: C#
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed

Drawing a Box With Rounded Corners in C#

I've talked quite a bit about different algorithms for manipulating images in various ways. Everything from convolution filters to contrast manipulation to even some procedural image generation such as perlin noise. However through all of that, I never really covered drawing your own images. Sure perlin noise is a form of drawing, I guess, but what if all you need is a box drawn around something? Are we out of luck, having to draw that pixel by pixel?

The quick answer is no, within the GDI framework there are a set of classes within the System.Drawing and System.Drawing.Drawing2D that allows us to draw various objects by calling their functions. For instance within the Graphics class we can draw arcs, rectangles, lines, etc. Each function is well documented and easy to use (just remember that 0,0 is the upper left hand corner of an image). However other than circles, arcs, lines, etc. there really isn't anything complex that it can draw for us. For instance there is no way to tell it that we want rounded corners. So for items like that we have to cobble the object together from what we're given. So lets look at how we would draw a box with rounded corners.

        /// <summary>
        /// Draws a rounded rectangle on a bitmap
        /// </summary>
        /// <param name="Image">Image to draw on</param>
        /// <param name="BoxColor">The color that the box should be</param>
        /// <param name="XPosition">The upper right corner's x position</param>
        /// <param name="YPosition">The upper right corner's y position</param>
        /// <param name="Height">Height of the box</param>
        /// <param name="Width">Width of the box</param>
        /// <param name="CornerRadius">Radius of the corners</param>
        /// <returns>The bitmap with the rounded box on it</returns>
        public static Bitmap DrawRoundedRectangle(Bitmap Image, Color BoxColor, int XPosition, int YPosition,
            int Height, int Width, int CornerRadius)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap, TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);

            Pen BoxPen = new Pen(BoxColor);
            GraphicsPath Path = new GraphicsPath();
            Path.AddLine(XPosition + CornerRadius, YPosition, XPosition + Width - (CornerRadius * 2), YPosition);
            Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition, CornerRadius * 2, CornerRadius * 2, 270, 90);
            Path.AddLine(XPosition + Width, YPosition + CornerRadius, XPosition + Width, YPosition + Height - (CornerRadius * 2));
            Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 0, 90);
            Path.AddLine(XPosition + Width - (CornerRadius * 2), YPosition + Height, XPosition + CornerRadius, YPosition + Height);
            Path.AddArc(XPosition, YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 90, 90);
            Path.AddLine(XPosition, YPosition + Height - (CornerRadius * 2), XPosition, YPosition + CornerRadius);
            Path.AddArc(XPosition, YPosition, CornerRadius * 2, CornerRadius * 2, 180, 90);
            Path.CloseFigure();
            NewGraphics.DrawPath(BoxPen, Path);
            NewGraphics.Dispose();
            return NewBitmap;
        }

The code above takes in a number of variables including the height, width, upper left hand corner position of the box, and the radius of the corners. The function then creates a Pen as well as a Path object. The Pen object defines what color and thickness the lines will be when we draw them. The Path object actually draws the box. It does this by drawing a line for each side and an arc at each corner. Once the box is drawn, it closes the figure, and tell the Graphics object to actually draw it on the image (note that doing this allows you to create one path and reuse it on multiple images, so you're not recreating it each time). That's all there is to it. So take a look at the Path class, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/5/2009 at 9:07 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed