dlras2
dlras2

Reputation: 8486

Inheriting an already instantiated base object

Is it possible to do something like the following:

public class ChildClass : BaseClass
{
    public ChildClass(BaseClass o)
    {
        base = o;
    }
}

Basically, I want a transparent way to wrap a base class inside of other functionality. One example I've thought of is a custom Settings Provider which transparently audits the settings passed through it.

public class SettingsAuditor : SettingsProvider
{
    public SettingsAuditor(SettingsProvider o)
    {
        base = o;
    }

    public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
    {
        // Log the property change to a file
        base.SetPropertyValues(context, propvals);
    }
}

Then I could do the following:

mySettingsProvider = new SettingsAuditor(mySettingsProvider);

And all changes would go through the overridden SetPropertyValues before passing to the original object.

I could use a private SettingsProvider member, but then I either cannot inherit from SettingsProvider, or have an entire SettingsProvider (base) not being used at all.

I'm using C# 4.0 and .Net 4.0.

Upvotes: 2

Views: 1260

Answers (4)

Matthew Whited
Matthew Whited

Reputation: 22443

This is not a complete implmentation and it could probably be done much cleaner with expression trees... but this was a quick swing at faking AOP using DynamicObject with .Net 4.0.

public class MyDynamicWrapper<T> : DynamicObject
{
    public T Wrapped { get; private set; }
    public Action<T> Pre { get; private set; }
    public Action<T> Post { get; private set; }


    public MyDynamicWrapper(T wrapped, Action<T> pre, Action<T> post)
    {
        this.Wrapped = wrapped;
        this.Pre = pre;
        this.Post = post;
    }

    public override bool TryGetMember(
        GetMemberBinder binder, 
        out object result)
    {
        var type = typeof(T);
        var method = type.GetMethod(binder.Name);
        if (method != null)
        {
            Func<object> func = () =>
            {
                if (Pre != null)
                    Pre(Wrapped);

                // support for input parameters could be added here
                var ret = method.Invoke(Wrapped, null);

                if (Post != null)
                    Post(Wrapped);
                return ret;
            };
            result = func;
            return true;
        }

        return base.TryGetMember(binder, out result);
    }
}
public class MyDynamicWrapper
{
    public static MyDynamicWrapper<T> Create<T>(
        T toWrap, 
        Action<T> pre = null, 
        Action<T> post = null)
    {
        return new MyDynamicWrapper<T>(toWrap, pre, post);
    }
}

public class MyObject
{
    public void MyMethod()
    {
        Console.WriteLine("Do Something");
    }
}

class Program
{
    static void Main()
    {
        var myobject = new MyObject();
        dynamic mydyn = MyDynamicWrapper.Create(
                                myobject, 
                                p => Console.WriteLine("before"), 
                                p => Console.WriteLine("after"));
        // Note that you have no intellisence... 
        // but you could use the old implmentation before you 
        //   changed to this wrapped version.
        mydyn.MyMethod();

        /* output below
        before
        Do Something
        after
        */
    }
}

Upvotes: 2

Jay
Jay

Reputation: 57919

  1. You cannot do base = o;
  2. What you're looking for is the Decorator Pattern), which is a way to compositionally add functionality at runtime (vs. inheritance).

Instead of trying to set the base, you just contain the inner member. As long as the wrapper implements the same interface or base class as the inner object, you can pass back the new wrapper. You can wrap as many decorators as you want.

Consider:

public interface ICar
{
    void Drive();
}

public class Car : ICar
{
    public void Drive()
    {
        Console.WriteLine("vroom");
    }
}

public class BuckleUp : ICar
{
    ICar car;

    public BuckleUp(ICar car) { this.car = car; }

    public void Drive()
    {
        Console.WriteLine("click!");
        car.Drive();
    }
}

public class CheckMirrors : ICar
{
    ICar car;
    public CheckMirrors(ICar car) { this.car = car; }

    public void Drive()
    {
        Console.WriteLine("mirrors adjusted");
        car.Drive();
    }
}

Now consider you have a method that accepts an ICar and tells it to drive. You could give it a Car, and it would work, but you could also wrap that car in a BuckleUp and a CheckMirrors and you wouldn't have to change that method at all. You've modified functionality through composition using the Decorator Pattern.

Upvotes: 4

James Curran
James Curran

Reputation: 103505

No, but you could fake it:

public class SettingsAuditor 
{ 
    SettingsProvider @base;

    public SettingsAuditor(SettingsProvider o) 
    { 
        @base = o; 
    } 

    public void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals) 
    { 
        // Log the property change to a file 
        @base.SetPropertyValues(context, propvals); 
    } 
} 

Note here, @base isn't the actual base, just a varaible named base

Upvotes: 0

Nix
Nix

Reputation: 58522

No. This looks like it should be a Composition vs Inheritance issue. You need to evaluate whether you are a "is a" or a "has a."

A little help for your journey

Upvotes: 2

Related Questions