Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在构造函数中不使用虚拟成员调用构造派生类属性_C#_Oop_Inheritance_Design Patterns - Fatal编程技术网

C# 在构造函数中不使用虚拟成员调用构造派生类属性

C# 在构造函数中不使用虚拟成员调用构造派生类属性,c#,oop,inheritance,design-patterns,C#,Oop,Inheritance,Design Patterns,我有一些嵌套类,BaseOuter和BaseInner,以及子类DerivedOuter和DerivedInnerBaseOuter具有属性BaseInner,当我实例化DerivedOuter时,我希望baseInner属性的运行时类型为DerivedInner 我首先像下面一样解决了这个问题,使用虚拟初始值设定项实例化baseInner,它在derivedouther中被重写。这允许我执行baseInner=newbaseinner()vsbaseInner=new-DerivedInner

我有一些嵌套类,
BaseOuter
BaseInner
,以及子类
DerivedOuter
DerivedInner
BaseOuter
具有属性
BaseInner,当我实例化
DerivedOuter
时,我希望
baseInner
属性的运行时类型为
DerivedInner

我首先像下面一样解决了这个问题,使用虚拟初始值设定项实例化
baseInner
,它在
derivedouther
中被重写。这允许我执行
baseInner=newbaseinner()vs
baseInner=new-DerivedInner()

在注意到a并做了a之后,我决定我应该改变它。。。但是怎么做呢

我想到了几件事。我可以在调用构造函数后调用初始值设定项,需要调用代码来执行
var baseOuter=new baseOuter();baseOuter.Initialize()。我也许可以用工厂,但我得考虑一下。最后,我想做的类嵌套中可能存在设计缺陷

值得指出的是,执行
newbaseinner()
非常昂贵,我不想简单地创建它然后扔掉

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;
            }
        }
    }
}
输出

new BaseOuter
BaseOuter Constructor
    BaseOuter Initialize BaseInner
        BaseInner Constructor

new DerivedOuter
BaseOuter Constructor
    DerivedOuter Initialize DerivedInner
        BaseInner Constructor
        DerivedInner Constructor
DerivedOuter Constructor (finished)
所有代码都可以在这里找到。

这里有一种方法

它也在做同样的事情。不同之处在于派生类如何“重写”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可能会这样建议。)

谢谢
BaseOuter
构造函数将有一行
baseInner=inner也是,对吗?是的,我漏了一行。基类将使用派生类提供的实现(如果有)。但是如果没有一个实例(它为null),那么它将指定自己的实例。值得一提的是,如果我们需要创建许多内部实例,我们可以传入一个委托函数来实现这一点,例如
(arg)=>new DerivedInner(arg)