Constructors … Hah!

Chad Myers asked:

How many, if any, of these kinds of statements should you see in your code:

ISomeService svc = ObjectFactory.GetObject<ISomeService>();

0? 1? Less than 12?

 

Later in the thread:

(Greg Young channelled Smashing Pumpkins when he said…)
> 0
So how do you kick the container off, like what Ayende said in the
Program.Main() call?

 

Quite simply I am working on a way to cheat. I am currently working on and I hope to have done + released in early January a mechanism for getting rid of constructors. I have some very basic tests passing now. Here is one, it might make things more clear.

A a = new A();
Assert.AreEqual(typeof(AProxy), a.GetType());

There are lots of reasons this can be good. Think about your IOC setups or for AOP if you use a dynamic proxy! My goal in taking on this project  is not to make this a production system frankly a post build step is a bad (read: fragile) way of doing this. My hope in this is to show the power that comes from this and to then lobby the CLR or C# team to build this for me natively.

I have a lot of difficult problems to solve still (especially with parameters) but here are the basics so people can comment on it and keep me from making bad decisions.

I run as a post build step. I find all places in code where a constructor is called and map them to my own generic mega-factory including the parameters associated with the constructor call. This factory dispatches the call to a delegate handler. As of now this handler is strongly typed …

Factory.Hook(new ConstructorOf<Foo>.WithSignature<string, int>.To( yourdelegate ))

The delegate signature would be Foo xxx(string, int)

If you have hooked a delegate to the constructor I will call your delegate anytime that the constructor is called as opposed to calling the constructor. You can in your delegate return a derived type etc (all without using factories).

If there is no handler registered I will generate a delegate dynamically that will just pass through and call the original constructor.

There are some really tough problems here, in particular because I am trying to make things completely transparent. As an example the following condition can happen.

private static void FooFactory(string _Param) {
    if(_Param == “greg”) return new FooProxy();
    return new Foo();
}

In this case I want the new FooProxy() to actually call back into the factory but I can’t let the new Foo() call come back to the factory (would produce infinite recursion). Since this is runtime configurable I also can’t do this at compile time (not that I could anyways because you could always generate code etc that made my assumptions invalid). So what I am left with is needing to have my generic factory look at the call stack (or keep a call stack) in order to figure out if you are already in a call of the same signature in your current construction operation. I think I will write this part quickly tomorrow and throw it up on my blog and give some performance analysis.

Thoughts?

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

11 Responses to Constructors … Hah!

  1. Greg says:

    Jonathan … I will not be using remoting contexts … they are *WAY* too slow and would lose transparency.

    I am doing this through IL re-writing. You methodology with the stack is similar to what I am doing now through. The problem is even that is a bit more of a perf hit than I would like to take.

    Also I am doing things in a strongly typed fashion which makes object MyNewIntercept(Type type, object[] params) fairly evil :)

     

    I’d be interested in hearing more about what you are trying to do though. 

    Cheers,

    Greg

  2. Another question — how are you planning on making this happen?

    There’s a project I’m working on that takes your objects and adds some wrapping code, and we’ve been thinking of setting it up to intercept new() like you’re talking about.

  3. To answer the question posed at the end of your post, you could put an object on the LogicalCallContext when you start your intercept and remove when your intercept processing is complete — something like this:

    object MyNewIntercept(Type type, object[] params)
    {
    if(null != InterceptContext && InterceptContext.Intercepts.Peek().Equals(new Intercept(type, params)))
    {
    return NonInterceptedObject();
    }
    try
    {
    if(null == InterceptContext)
    {
    InterceptContext = new InterceptContext();
    }
    InterceptContext.Intercepts.Push(new Intercept(type, params));
    // normal intercept processing here
    }
    finally
    {
    InterceptContext.Pop();
    If(InterceptContext.Intercepts.Count == 0)
    {
    InterceptContext = null;
    }
    }
    }

    static InterceptContext Context
    {
    get { return (GenerationContext)System.Runtime.Remoting.Messaging.CallContext.GetData(“InterceptContext “); }
    set { System.Runtime.Remoting.Messaging.CallContext.SetData(“InterceptContext”, value); }
    }

  4. Greg says:

    Typo: sorry Kent I updated it.

  5. Kent Alstad says:

    Greg the lines of code that you intended to clear things up have confused me.

    A a = new A();
    Assert.AreEqual(typeof(AProxy), false.GetType());

    I would have thought that you want to assert that AProxy and a are the same. Can you please explain this code more fully.

  6. Greg says:

    not really Jeff.

    1) that is *really* slow.
    2) I want to be able to trap the FooDecorator constructor there and allow remapping of it.
    3) it feels unnatural to put such a requirement (what happens if they forget? stackoverflow?)

  7. JeffyW says:

    In C#, you could avoid your problem by taking advantage of the Activator class:

    private static void FooFactory(string _Param) {
    if(_Param == “greg”) return Activator.CreateInstance();
    return Activator.CreateInstance();
    }

  8. Greg says:

    As of now I was using cecil but I will take a good look at postsharp as it may save me some time.

  9. cmyers says:

    Greg, thanks for blogging this! It was my hope that the altnetconf list would produce more and better blog posts and it’s starting to now! Please keep it up. Great stuff!

  10. cristian says:

    Sounds interesting. Are you going to use postsharp for this? Looks a bit like something I’ve imagined seeing on ruby constructors

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>