构造派生类属性而无需在构造函数中进行虚拟成员调用

时间:2018-12-04 15:03:53

标签: c# oop inheritance design-patterns

我有一些嵌套类-fltoBaseOuter,还有子类BaseInnerDerivedOuterDerivedInner具有属性BaseOuter,当实例化BaseInner baseInner;时,我希望DerivedOuter属性的运行时类型为baseInner

我首先像下面一样解决了这个问题,使用虚拟初始化器实例化DerivedInner,该初始化器在baseInner中被覆盖。这样一来,我就可以在各自的初始化程序中进行DerivedOuterbaseInner = new BaseInner();的对比。

注意到Resharper warning并做了little more reading之后,我决定应该更改它……但是如何?

我想到了几件事。我可以在调用构造函数之后调用初始化程序,这需要调用代码来完成baseInner = new DerivedInner();。我可能可以使用工厂,但是我必须考虑一下。最后,也许我想做的类嵌套中存在设计缺陷?

值得指出的是,var baseOuter = new BaseOuter(); baseOuter.Initialize();的执行成本很高,而且我并不仅仅是想创建它并扔掉它。

new BaseInner();

输出

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("new BaseOuter");
        var baseOuter = new BaseOuter();
        Console.WriteLine("\nnew DerivedOuter");
        var derivedOuter = new DerivedOuter();
    }

    class BaseOuter{
        protected BaseInner baseInner;
        public BaseOuter(){
            Console.WriteLine("BaseOuter Constructor");
            /*  lots of stuff I want in derived class */

            // This is an anti-pattern I want to avoid
            //https://www.jetbrains.com/help/resharper/2018.2/VirtualMemberCallInConstructor.html
            InitializeInner();
        }

        protected virtual void InitializeInner(){
            Console.WriteLine("    BaseOuter Initialize BaseInner");
            baseInner = new BaseInner();
        }

        protected class BaseInner{
            public int x;
            public BaseInner(){
                /* stuff that is needed in DerivedInner too */
                Console.WriteLine("        BaseInner Constructor");
                x = 2;
            }
        }       
    }

    class DerivedOuter : BaseOuter {
        public DerivedOuter() {
            Console.WriteLine("DerivedOuter Constructor (finished)");
        }

        protected override void InitializeInner(){
            Console.WriteLine("    DerivedOuter Initialize DerivedInner");
            baseInner = new DerivedInner();
        }

        protected class DerivedInner : BaseInner {
            public double y;
            public DerivedInner(){
            Console.WriteLine("        DerivedInner Constructor");
                y = 2d;
            }
        }
    }
}

所有代码都可以在此.NET Fiddle中找到。

1 个答案:

答案 0 :(得分:1)

这是一种方法。

它在做同样的事情。区别在于派生类如何“替代” BaseInner的实现。它通过向构造函数提供实现来实现。

internal class BaseOuter
{
    protected BaseInner baseInner;

    protected internal BaseOuter(BaseInner inner = null)
    {
        baseInner = inner ?? new BaseInner();
        Console.WriteLine("BaseOuter Constructor");
        /*  lots of stuff I want in derived class */

        // This is an anti-pattern I want to avoid
        //https://www.jetbrains.com/help/resharper/2018.2/VirtualMemberCallInConstructor.html

    }

    protected internal class BaseInner
    {
        public int x;

        public BaseInner()
        {
            /* stuff that is needed in DerivedInner too */
            Console.WriteLine("        BaseInner Constructor");
            x = 2;
        }
    }
}

internal class DerivedOuter : BaseOuter
{
    protected internal DerivedOuter()
     :base(new DerivedInner())
    {
        Console.WriteLine("DerivedOuter Constructor (finished)");
    }

    protected internal class DerivedInner : BaseInner
    {
        public double y;

        public DerivedInner()
        {
            Console.WriteLine("        DerivedInner Constructor");
            y = 2d;
        }
    }
}

如果要进行全面的依赖注入,则可以从

中删除默认值
protected internal BaseOuter(BaseInner inner = null)

这意味着BaseOuter将与BaseInner的任何实现完全脱钩。

其他一些建议:

  • 除非有非常强烈的需求,否则我不会彼此嵌套类。它使用不多,因此乍一看可能会使人感到困惑。
  • 如果应该仅在调用构造函数时设置baseInner,则将其标记为readonly。 (ReSharper可能会建议。)