Roy T.
Roy T.

Reputation: 9638

Wrapping a class while still exposing all its public methods, properties and fields

I'm trying to make a generic wrapper class that can wrap any other class and add extra functionality to it. However at the same time I want to be able to use this wrapper everywhere where I would normally use the wrapped class. Currently I use implicit casting which works OK. But in an ideal world I would like to the wrapper class to have the same exposed methods and fields as the wrapped class, like in this piece of example code:

class Foo
{   
    public int Bar() { return 5; }
}

class Wrapper<T>
{
    private T contents;

    public void ExtraFunctionality() { }
    public static implicit operator T(Wrapper<T> w) { return w.contents; }
}



Foo f = new Foo();
Wrapper<Foo> w = new Wrapper<Foo>(foo);

int y = w.Bar();

Can I use some ancient witchcraft, reflection, or other trickery to make this possible?

Note: in C++ I would just overload the -> operator to operate on the field contents instead of on the wrapper.

Upvotes: 1

Views: 3747

Answers (2)

dcastro
dcastro

Reputation: 68710

I wouldn't recommend this, but since you've mentioned witchcraft... you can use dynamic typing with DynamicObject. The wrapper tries to handle the requested method. If it can't, it forwards the call to the underlying wrapped object:

class DynamicWrapper : DynamicObject
{
    private readonly object _contents;

    public DynamicWrapper(object obj)
    {
        _contents = obj;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        if (binder.Name == "ExtraFunctionality")
        {
            // extra functionality
            return true;
        }
        var method = _contents.GetType()
                             .GetRuntimeMethods()
                             .FirstOrDefault(m => m.Name == binder.Name);

        if (method == null)
        {
            result = null;
            return false;
        }

        result = method.Invoke(_contents, args);
        return true;
    }
}

Edit:

Nevermind, I just noticed you wanted to use an instance of this everywhere where you would normally use an instance of the wrapped type. You'd have to change the field/property/variable declaration to dynamic to use this.

Upvotes: 1

Markus
Markus

Reputation: 22481

You can generate the type(s) dynamically using the classes in the System.Reflection.Emit namespace. This link can give you a good starting point.

Upvotes: 0

Related Questions