Question

I want to make this test pass - anyone got an idea how to do that?

public class Something
{
    public string Name {get; set}
}

public interface IWithId
{
    public Guid Id {get; set}
}

public class IdExtender 
{
    public static Object Extend(object toExtend)
    {
        ...?
    }
}

public class Tests 
{
    [Test]
    public void Should_extend_any_object()
    {
        var thing = new Something { Name = "Hello World!"};
        var extended = IdExtender.Extend(thing);
        Assert.IsTrue(extended is IWithId);
        Assert.IsTrue(extended.Id is Guid);
        Assert.IsTrue(extened.Name == "Hello World!");
    }
}

I guess something like this could be done with castle dynamic proxy, linfu,etc... but how?

Was it helpful?

Solution

Using Castle DP (obviously)

Well - you will have to create a new object to return since you can't have an existing type gain a new interface as your program is executing.

To do this you will need to create a proxy and then replicate the state of your pre-existing object onto the proxy. DP does not do that OOTB. In v2.5 you could use the new class proxy with target but that would work only if all the properties on the type were virtual.

Anyway. You can make the new type gain the IWithId interface either by mixing in the proxy with an existing object that implement the property. Then the calls to members of the interface will be forwarded to the object.

Alternatively you can provide it as additional interface to implement and have an interceptor fill in the role of implementor.

OTHER TIPS

For now I am going with linfu like this:

public class IdExtender 
{
    public static Object Extend(object toExtend)
    {
        var dyn = new DynamicObject(toExtend);
        dyn.MixWith(new WithId {
                                Id = Guid.New()
                               });
        var extended = dyn.CreateDuck<IWithId>(returnValue.GetType().GetInterfaces());
        return extended;
    }
}

Why not use a mocking framework like Moq or RhinoMocks. They allow you to dynamically implement interfaces without the hastle of creating a proxy directly.

With Moq you could write:

var mock = new Mock<IWithId>();  // mock the interface
mock.Setup(foo => foo.Name).Returns("Hello World"); // setup a property

Aside from that, you would have to do some complicated work to get what you want. As far as I know, you cannot add method or properties to an existing class at runtime. You could return an instance of a new object that dynamically inherits from the type passed in. Castle definitely allows this, but the code necessary is not especially elegant, or simple.

Setting aside the question of how to dynamically attach a property or interface, it sounds like what you're attempting to do is augment existing classes with additional data. A very typical solution to this problem is to use a Dictionary<Something, SomethingExtra> and store it in some service class that maintains the mapping. Now, when you need access to SomethingExtra, you just ask the service class for the associated information.

Advantages:

  1. The implementation is easier to understand and maintain than a solution using reflection and dynamic proxy generation.

  2. If you need to derive from the type being extended, the class can't be sealed. Associating information externally works fine with sealed classes.

  3. You can associate information without having to be responsible for the construction of the augmented object. You can take instances created anywhere and associate the new information.

Disadvantages:

  1. You need to inject the service instance that maintains the mapping. You can do this via an IoC framework if you're using one, manual injection (usually passed through a constructor) or, if there's no other alternative, via a Singleton static accessor.

  2. If you have a very large number of instances and they are being rapidly created/removed, the Dictionary overhead could become noticeable. I suspect you would need some very heavy load before the overhead becomes noticeable compared to a proxying implementation.

I have actually answered a similar question last week. I have also written a little library that does this one thing. It is available from my blog, which I am shamelessly plugging.

What you are after is almost achievable using Castle Dynamic Proxy. The only constraint is that the existing instance must implement an interface and all the properties/methods you are interested in are available through that interface.

public static TIntf CreateMixinWithTarget<TIntf>(TIntf target, params object[] instances) where TIntf : class{

    ProxyGenerator generator = new ProxyGenerator();
    ProxyGenerationOptions options = new ProxyGenerationOptions();

    instances.ToList().ForEach(obj => options.AddMixinInstance(obj));

    return generator.CreateInterfaceProxyWithTarget <TIntf>(target, options);
}

[Test]
public void Should_extend_any_object()
{
    var thing = new Something { Name = "Hello World!"};
    var extended = CreateMixinWithTarget<ISomething>(thing, new WithId(), new GuidImpl());
    Assert.IsTrue(extended is IWithId);
    Assert.IsTrue(extended.Id is Guid);
    Assert.IsTrue(extened.Name == "Hello World!");
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top