Wiki

Clone wiki

CodeCop / Type Creation API

Type Creation API

Starting from v3.1 CodeCop has widen its scope and now let's you create types at runtime without the need of dynamic compilation or dynamic assemblies. When creating a type you can specify things like inheritance, interfaces, constructor, fields, properties, methods and attributes, in a managed and fluent way, almost resembling F# object expressions. The API is composed of these 16 methods:

TypeCreationIntent Let(string name)

This method belongs to be Cop class and returns a TypeCreationIntent object. This object is your type metadata builder that the CodeCop runtime needs to generate a new type.

TypeMetadata With()

This method belongs to the TypeCreationIntent class and returns a TypeMetadata object. This is what bootstraps the internal metadata writing process for your new type.

TypeMetadata Parent<T>()

This generic method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds inheritance information to your new type's metadata. Parent must be a public class.

TypeMetadata Parent(Type parentType)

The non-generic version of the previous method.

TypeMetadata Attribute<T>()

This generic method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds attribute information to your new type's metadata.

TypeMetadata Attribute(Type attributeType)

The non-generic version of the previous method.

TypeMetadata Implementing<T>(MethodBase interfaceMethod, Delegate implementation)

This generic method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds interface information to your new type's metadata as well as the delegate responsible for a concrete method implementation.

TypeMetadata Implementing(Type interfaceType, MethodBase interfaceMethod, Delegate implementation)
The non-generic version of the previous method.

TypeMetadata Implementing<T>(MethodBase interfaceMethod, Delegate implementation)
An overload to the previous generic method that takes a method name instead of a method base, use this only if there are no overloads to the interface method you are implementing.

TypeMetadata Implementing(Type interfaceType, string interfaceMethodName, Delegate implementation)
The non-generic version of the previous method.

TypeMetadata Constructor(Delegate constructor)
This method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds constructor information to your new type's metadata as well as its behavior in a form of a Delegate object.

TypeMetadata Field<T>(string fieldName)

This generic method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds field information to your new type's metadata. NOTE: No generic fields are supported at this stage, you should use the object type and perform a cast at runtime.

TypeMetadata Field(Type fieldType, string fieldName)

The non-generic version of the previous method.

TypeMetadata Property(string propertyName, Delegate getter, Delegate setter)

This method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds property information to your new type's metadata. Getter and Setter is represented as Delegates and should always be specified.

TypeMetadata Method(string methodName, Delegate methodBody)

This method belongs to the TypeCreationIntent class and returns a TypeMetadata object. Adds method information to your new type's metadata. The "body" of the method or its behavior is represented as a Delegate.

Type Create()

This method belongs to the TypeCreationIntent class and returns a Type object. Instructs the CodeCop runtime to create a new type based on the metadata that was built via the TypeMetadata object.

Quick example

Here's an example of how to create a new Serializable and Disposable type that has an int field a property and a void method as members.

 public class SomeParentClass
{
    public void SomeParentMethod()
    {
        Console.WriteLine("SomeParentMethod Logic...");
    }
}

public class Program
{
    static void Main(string[] args)
    {
        // Tell CodeCop to use the Fluent API 
        Cop.AsFluent();

        // Create a new type
        var newType = Cop
                        .Let("NewType")
                        .With()
                        .Parent<SomeParentClass>()
                        .Attribute<SerializableAttribute>()
                        .Implementing<IDisposable>("Dispose",
                         new Action(() =>
                         {
                             Console.WriteLine("Dispose Logic...");
                         }))
                        .Constructor(
                         new Action(() =>
                         {
                             Console.WriteLine("Constructor logic...");
                         }))
                        .Field<int>("SomeField")
                        .Property("SomeProperty",
                         new Func<int>(() =>
                         {
                             Console.WriteLine("Getter logic...");
                             return 1;
                         }),
                         new Action<int>((x) =>
                         {
                             Console.WriteLine("Setter logic...");
                         }))
                        .Method("SomeMethod",
                         new Action(() =>
                         {
                             Console.WriteLine("SomeMethod logic...");
                         }))
                        .Create();

        // Print the type to the console to see that resides on mscorlib
        Console.WriteLine("Type Name: {0} Assembly: {1}", newType.FullName, newType.Assembly.FullName);

        // Check to see if it is Serializable
        Console.WriteLine("{0} is Serializable? {1}", newType.Name, newType.IsSerializable);

        // Instantiate it
        dynamic instance = Activator.CreateInstance(newType);

        // Cast it to parent class
        SomeParentClass parent = instance;

        // Call a method on parent class
        parent.SomeParentMethod();

        // Call its members
        instance.SomeField = 10;

        instance.SomeProperty = 1;
        var propValue = instance.SomeProperty;

        instance.SomeMethod();

        // Dispose it via its IDisposable implementation
        (instance as IDisposable).Dispose();
    }
}

Here's the output result:

screen3.jpg

Notes: All members are declared with a public visibility, all types are attached to the mscorlib assembly. If you are returning or using types that reside outside the mscorlib assembly, the containing assembly must be signed.

Updated