Наследование уже созданного базового объекта - PullRequest
2 голосов
/ 05 августа 2010

Можно ли сделать что-то вроде следующего:

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, либовесь SettingsProvider (base) вообще не используется.

Я использую C # 4.0 и .Net 4.0.

Ответы [ 4 ]

4 голосов
/ 05 августа 2010
  1. Вы не можете сделать base = o;
  2. То, что вы ищете, это Pattern Decorator ), который является способом композиционного добавления функциональности во время выполнения (по сравнению с наследованием).).

Вместо того, чтобы пытаться установить 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, и это сработало бы, но вы могли бы также обернуть эту машину в BuckleUp и CheckMirrors, и вам не пришлось бы вообще менять этот метод.Вы изменили функциональность с помощью композиции, используя Pattern Decorator .

2 голосов
/ 05 августа 2010

Это не полная реализация, и, вероятно, ее можно было бы сделать намного чище с деревьями выражений ... но это был быстрый шаг при фальсификации AOP с использованием DynamicObject с .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
        */
    }
}
2 голосов
/ 05 августа 2010

Нет. Похоже, что это должна быть проблема «Композиция против наследования». Вам необходимо оценить, являетесь ли вы «есть» или «есть».

Небольшая помощь для вашего путешествия

0 голосов
/ 05 августа 2010

Нет, но вы могли бы подделать это:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...