Sunday, July 15, 2007

Introspection vs. Reflection for Spring.NET

Why "versus"?

It can be hard to explain what the difference between the two is, so I'll quote the veteran of the windows programming and debugging - John Robbins:

When I first started looking at rule development, I couldn't quite get my head around what the Introspection engine was doing. After a while, it finally dawned on me that the way to think about it was that Introspection is just manual reflection. Whereas reflection loads up the assembly and calls the types and other information in the assembly, the Introspection engine maps the assembly into memory and goes through the grind of walking all the internal tables by hand. Interestingly, if you start looking hard at the Introspection engine with the Reflector tool, you'll see that through Introspection, it also supports creating code, much like the Reflection.Emit namespace.

What is the problem for Spring.NET?

Currently, Spring.NET is using reflection and that is probably the only option at the moment that is coming for "free" with no further license implications.

Except for speed and locking, when reflection is falling short compared to the introspection?

Reflection is not providing for restoration of all of the constructs you may use in your code.


For example for custom attribute definition like:

    public class TestAttribute : Attribute
    {
        private int firstGetterOnlyPropertyValue;
        private int secondGetterOnlyPropertyValue;
        private string readWriteProperty;

        public TestAttribute(int firstGetterOnlyProperty)
        public TestAttribute(int firstGetterOnlyProperty, int secondGetterOnlyPropertyValue)
        public int FirstGetterOnlyProperty
        public int SecondGetterOnlyProperty
        public string ReadWriteProperty
    }

Imagine that we want to create a copy of this attribute from the original type to put it in a proxy. Thanks to reflection we know all the constructors the type has got, but we don't know which constructor was used to create this attribute actually. We can't just assign all properties after the creation of an attribute with a default constructor, because:

1. Property may be read only.

2. Property value from the original type set by default may not be correctly assignable to the target type (e.g. ConfigurationName of the ServiceBehaviorAttribute is null by default, but you can't set it to null via property assignment)

We may speculate that we can deduce the constructor from types and their order (not in our test case, both int, "first, second" in the names can be misleading), which can be very error-prone.

Solution beer bash*.

Probably ideal solution would be able to read the PE (Portable Executable) and tell us exactly the nuances of how attribute was applied to the member.

As I have not tried introspection by myself the following section is more about making assumptions based onto John Robbin's "Debugging .NET 2.0 Applications" book, msdn and Reflector.

Use FxCop introspection libraries to fill the gap.

FxCop library Api seems to be very focused onto the "rules" concept only, though most importantly it traverses all of the modules and members giving us an opportunity to inspect them.

Microsoft.Cci library has AttributeNode with the following type information:

public class AttributeNode : Node
{
    // Fields
    private bool allowMultiple;
    public Expression Constructor;
    public static readonly AttributeNode DoesNotExist;
    public ExpressionList Expressions;
    private bool inherited;
    public bool IsPseudoAttribute;
    public AttributeTargets Target;
    private TypeNode type;
    private AttributeNode usageAttribute;
    private AttributeTargets validOn;

    // Methods
    static AttributeNode();
    public AttributeNode();
    public AttributeNode(Expression constructor, ExpressionList expressions);
    public AttributeNode(Expression constructor, ExpressionList expressions, AttributeTargets target);
    private Attribute ConstructAttribute(InstanceInitializer constr, object[] argumentValues);
    protected Array GetCoercedArrayLiteral(ArrayType arrayType, Array arrayValue);
    protected object GetCoercedLiteralValue(TypeNode type, object value);
    public Expression GetNamedArgument(Identifier name);
    public Expression GetPositionalArgument(int n);
    public virtual Attribute GetRuntimeAttribute();
    private void GetUsageInformation();
    private void SetAttributeProperty(Property prop, Attribute attr, object val);

    // Properties
    public virtual bool AllowMultiple { get; set; }
    public virtual bool Inherited { get; set; }
    public virtual TypeNode Type { get; set; }
    public virtual AttributeTargets ValidOn { get; set; }
}

 

Where constructor of type Expression is available as a public field as well as there is an interesting method ConstructAttribute returning directly the attribute instance.
I'd speculate that Expression for the constructor would contain stuff required to instantiate the attribute exactly in the way that it is declared on a member..

That's it for the FxCop for now. I'm not going to go into more details..

Anything else (suitable for OSS**) out there to parse PEs?

Crawling through the web gave only following:

http://www.plas.fit.qut.edu.au/perwapi/

I'll take a look into this option for the next blog entry.

References and additional info:

Spring.NET jira issue as an entry point to forum discussions:
http://opensource.atlassian.com/projects/spring/browse/SPRNET-606
Interesting: object initializers in C# 3.0: http://blogs.msdn.com/wriju/archive/2007/04/12/c-3-0-enhancements-object-initializers.aspx

* beer bash = Irish for brain storming :).
**OSS - Open Source Software

No comments: