C# 通过包装类重写类方法

C# 通过包装类重写类方法,c#,inheritance,architecture,polymorphism,C#,Inheritance,Architecture,Polymorphism,我试图想出一个非常简洁的方法来改变现有的类。我将尝试用这个例子来解释我的想法 abstract class AbstractX { public abstract string X(); protected internal abstract int Y(); } // Execute all methods on another instance of AbstractX // This is why the method(s) are 'protected *interna

我试图想出一个非常简洁的方法来改变现有的类。我将尝试用这个例子来解释我的想法

abstract class AbstractX
{
    public abstract string X();
    protected internal abstract int Y();
}

// Execute all methods on another instance of AbstractX
// This is why the method(s) are 'protected *internal*'
class WrappedX : AbstractX
{
    AbstractX _orig;
    public WrappedX(AbstractX orig)
    {
        _orig = orig;
    }

    public override string X()
    {
        return _orig.X();
    }
    protected internal override int Y()
    {
        return _orig.Y();
    }
}

// The AbstractX implementation I start with
class DefaultX : AbstractX
{
    public override string X()
    {
        // do stuff

        // call Y, note that this would never call Y in WrappedX
        var y = Y();

        return y.ToString();
    }
    protected internal override int Y()
    {
        return 1;
    }
}

// The AbstractX implementation that should be able to alter *any* other AbstractX class
class AlteredX : WrappedX
{
    public AlteredX(AbstractX orig)
        :base(orig)
    {
    }

    protected internal override int Y()
    {
        Console.WriteLine("Sweet, this can be added to any AbstractX instance!");

        return base.Y();
    }
}
对,所以我打算用的方式是,

AbstractX x = new DefaultX();
x = new AlteredX(x);
Console.WriteLine(x.X()); // Should output 2 lines
或者暂时远离抽象的例子,让它更具体(应该是不言自明的)

但是(回到抽象的例子)这是行不通的。调用
AlteredX.X()
的那一刻(它没有被覆盖),它会转到
WrappedX.X()
,当然它运行
DefaultX.X()
,它使用自己的
Y()
方法,而不是我在
AlteredX中定义的方法。
它甚至不知道它的存在

我希望这是显而易见的为什么我希望这是工作,但我会进一步解释,以确保

如果我不使用
WrappedX
创建
AlteredX,
AlteredX将不会“适用”于任何AbstractX实例, 这样就不可能像上面的
FileWriter
那样。而不是

FileWriterAbstract
FileWriterDefault : FileWriterAbstract
FileWriterWrap : FileWriterAbstract
FileWriterSplit : FileWriterWrap
FileWriterLogged : FileWriterWrap
它将成为,

FileWriterAbstract
FileWriterDefault : FileWriterAbstract
FileWriterSplit : FileWriterDefault
// Implement Logged twice because we may want to use it with or without Split
FileWriterLogged : FileWriterDefault
FileWriterLoggedSplit : FileWriterSplit
如果我创建了一个新的,我必须实现它4次,因为我想让它可以用

Default
Split
Logged
Split+Logged
等等

考虑到这一点,实现这一目标的最佳方式是什么?我能想到的最好的(未经测试)是

classdefaultx:AbstractX
{
受保护的内部重写Func xf{get;set;}
受保护的内部重写函数yf{get;set;}
公共默认值x()
{
xf=XDefault;
yf=故障;
}
公共重写字符串X()
{
返回xf();
}
受保护的覆盖int Y()
{
返回yf();
}
字符串XDefault()
{
var y=y();
返回y.ToString();
}
int故障()
{
返回1;
}
}
类AlteredX:WrappedX
{
Func_yfOrig{get;set;}
公共AlteredX()
{
//我假设在设置时不会覆盖该类成员
//下面一行中的base.yf。
_yfOrig=base.yf;
base.yf=yalter;
}
私家侦探()
{
WriteLine(“很好,这可以添加到任何AbstractX实例中!”);
返回yfOrig();
}
}

即使这真的有效,它看起来真的很混乱。。。有人有什么建议吗?

我想你把作文和继承弄混了

在AlteredX对象上调用x.x()时,该对象将调用其基本对象(WrappedX)的x方法。基本对象本身调用已包装的DefaultX类型的对象。现在对DefaultX(_orig)的对象调用Y方法。您希望(u orig)知道调用方的调用方中存在被覆盖的内容!但是怎么做呢


在这个调用链中,我看不到涉及重写方法Y的任何点。

处理这个问题的一种方法是将所有内部操作推迟到一个单独的、可能的内部实用程序类,并为包装类提供一种替换实用程序类实现的方法。注意:此示例需要任何具体的非包装类来实现实用程序类。包装类可以选择也可以不选择包装实用程序类。这里的关键是基(抽象)类中实用程序类的getter/setter不允许重写它,因此每个继承类都使用由其构造函数定义的实用程序类。如果它选择不创建自己的实用程序,它将默认为它所包装的类的实用程序,最终使其返回到具体的、未包装的组合根类(如果需要)

注意:这非常复杂,我会避免这样做。如果可能,请使用标准装饰器,并且仅依赖包装类的公共接口方法。此外,实用程序类不必是内部类。它们可以通过构造函数注入,这可能会使它更干净一些。然后,您还可以在实用程序上显式地使用Decorator模式

public interface IFoo
{
    string X();
}

public abstract class AbstractFoo : IFoo
{
    public abstract string X();

    protected internal Footilities Utilities { get; set; }

    protected internal abstract class Footilities
    {
        public abstract int Y();
    }
}

public class DefaultFoo : AbstractFoo
{
    public DefaultFoo()
    {
        Utilities = new DefaultFootilities();
    }

    public override string X()
    {
        var y = Utilities.Y();

        return y.ToString();
    }

    protected internal class DefaultFootilities : Footilities
    {
        public override int Y()
        {
            return 1;
        }
    }
}

public abstract class AbstractWrappedFoo : AbstractFoo
{
    protected readonly AbstractFoo Foo;

    public AbstractWrappedFoo(AbstractFoo foo)
    {
        Foo = foo;
    }

    public override string X()
    {
        return Foo.X();
    }
}

public class LoggedFoo : AbstractWrappedFoo
{
    public LoggedFoo(AbstractFoo foo)
        : base(foo)
    {
        Foo.Utilities = new LoggedUtilities(Foo.Utilities);
    }

    public override string X()
    {
        return Foo.X();
    }


    protected internal class LoggedUtilities : Footilities
    {
        private readonly Footilities _utilities;

        public LoggedUtilities(Footilities utilities)
        {
            _utilities = utilities;
        }

        public override int Y()
        {
            Console.WriteLine("Sweet");
            return _utilities.Y();
        }
    }
}
现在这个节目

class Program
{
    static void Main(string[] args)
    {
        AbstractFoo foo = new LoggedFoo(new DefaultFoo());

        Console.WriteLine(foo.X());
    }
}
产生

Sweet!
1

你所想到的看起来像是装饰图案,@Alireza我知道,这并没有改变我正在寻找问题解决方案的事实。@tvanfosson是的,看起来像。那个wiki页面只显示了一些示例,这些示例并不试图覆盖公共方法调用的特定方法,所以我的问题是,你把问题通读了吗?我已经知道这是一个问题,但我仍然在寻找一个解决方案来做我正在尝试做的事情。谢谢你的回答。在许多方面,这与我在问题末尾的内容相同,只是您使用的是类而不是Action/Func。我想这意味着没有更好的选择了,所以我会坚持下去。@natli看起来都太复杂了,但考虑到一个抽象的问题,很难给你更好的建议。我想我应该尝试删除内部/受保护方法的重用。在实际问题中,如果看不到你在做什么,很难说怎么做。
class Program
{
    static void Main(string[] args)
    {
        AbstractFoo foo = new LoggedFoo(new DefaultFoo());

        Console.WriteLine(foo.X());
    }
}
Sweet!
1