继承已经实例化的基础对象

时间:2010-08-05 13:55:16

标签: c# .net inheritance

是否可以执行以下操作:

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

基本上,我想要一种透明的方法将基类包装在其他功能中。我想到的一个例子是自定义设置提供程序,它透明地审核通过它的设置。

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);
    }
}

然后我可以做以下事情:

mySettingsProvider = new SettingsAuditor(mySettingsProvider);

在传递给原始对象之前,所有更改都将通过被覆盖的SetPropertyValues

我可以使用私人SettingsProvider成员,但是我要么无法继承 SettingsProvider中的,要么拥有整个SettingsProviderbase )根本没用。

我正在使用C#4.0和.Net 4.0。

4 个答案:

答案 0 :(得分:4)

  1. 您不能base = o;
  2. 您正在寻找的是Decorator Pattern),这是一种在运行时(相对于继承)组合添加功能的方法。
  3. 您只需包含内部成员,而不是尝试设置base。只要包装器实现与内部对象相同的接口或基类,就可以传回新的包装器。您可以根据需要包装任意数量的装饰器。

    考虑一下:

    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();
        }
    }
    

    现在考虑你有一个方法接受ICar并告诉它开车。您可以给它一个Car,它会起作用,但您也可以将该车包裹在BuckleUpCheckMirrors中,您根本不需要更改该方法。您已使用Decorator Pattern修改了合成功能。

答案 1 :(得分:2)

没有。这看起来应该是一个Composition vs Inheritance问题。您需要评估自己是“是”还是“有”。

A little help for your journey

答案 2 :(得分:2)

这不是一个完整的实现,它可能可以用表达式树做得更干净......但是这是使用动态对象与.Net 4.0伪造AOP的快速转变。

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
        */
    }
}

答案 3 :(得分:0)

不,但你可以伪造它:

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); 
    } 
} 

请注意,@ base不是实际的基础,只是名为base

的变量