//如下代码:
abstract class baseclass{
    baseclass(){
       callA();
    }
    virtual void callA();
}class newclass:basseclass{
    newclass();
    override void callA(){};
}baseclass中callA()因为会出现初始化顺序错误会出现警告,问题是这种情况下如何才是正确的使用多态的方法?

解决方案 »

  1.   

    abstract class baseclass
        {
           protected baseclass()
            {
                callA();
            }
          public  abstract  void callA();
        }    class newclass : baseclass
        {
            public newclass() { }
            public override void callA()
            {
                Console.WriteLine("new class implement!");
            }
        }    class Program
        {        static void Main(string[] args)
            {
                baseclass mybase = new newclass();        }
        }
      

  2.   

    构造函数中不要调用任何未封闭的方法,因为虚方法可能会调用了未初始化的字段
    反例:
        abstract class baseclass
        {
            protected baseclass()
            {
                callA();
            }
            public  abstract  void callA();
        }    class newclass : baseclass
        {
            object _obj;
            public newclass()
            {
                _obj = new object();
            }
            public override void callA()
            {
                Console.WriteLine(_obj.GetType());//空引用
            }
        }
      

  3.   

    如果是自己设计的类,则改掉这个做法,不要在构造函数中调用虚方法,如果一定要在构造以后调用这个虚方法,那么最好是在使用New建立对象后主动的调用虚方法,比如:
    baseclass bc=new baseclass();
    bc.callA();这样就避免了任何初始化的问题,并且是合理的。
    不需要也不可以把虚方法在构造函数中调用。
      

  4.   

    vwxyzh:谢谢。
    你说的这个我知道。正是因为如此,如何尝试用多态,让每个派生类在构造的时候能执行callA中相应的操作(当然可以不执行callA)?
      

  5.   

    基类callA函数声明为abstract或者加上基类实现不可以么?
      

  6.   

    平民百姓:非常感谢
    我希望派生类构造完成以后对callA的调用时透明的。不需要在子类中进行维护。
    完成newclass编码的人不需要了解在类使用时的场景,类使用的人也不需要记住baseclass bc=new   baseclass(); 后还要bc.callA(); 减少编码出错的概率。interface IMyInterface{
       void callA();
    }abstract class baseclass:IMyInterface
        {
            protected baseclass()
            {
                callA();
            }
        }    class newclass : baseclass
        {        public newclass()
            {
                //不需要在此处做处理
            }
            public override void callA()
            {
                //something here
            }
        }
      

  7.   

    soaringbird :谢谢。
    如果是sealed类是可以的。当有派生类时会在构造函数初始化时出现问题。就像2楼yzh所描述的那样。
      

  8.   

    @soaringbird
    编译确实没有警告,代码分析会有警告
    @lz
    考虑用Builder模式
      

  9.   

    我也是考虑用什么样的模式。yzh,能说说看builder模式能怎样避免这个问题?先谢了
      

  10.   

    这个试了 可以执行 不知道是否合要求
    interface IMyInterface
        {
            void callA();
        }     abstract class baseclass:IMyInterface
        {
           protected baseclass()
            {
                callA();
            }
               public virtual void callA()
            {
                Console.WriteLine("base implement!");
            } 
        }    class newclass : baseclass
        {
            public newclass() { }
            public override void callA()
            {
                Console.WriteLine("newclass implemented");
            }
        }    class Program
        {        static void Main(string[] args)
            {
                newclass myn = new newclass();        }
        }
      

  11.   

    对于二楼的反例,可以考虑把 _obj = new object();放到CallA()里面。
    在写这种代码时,一定要注意执行顺序。
      

  12.   

    看来builder模式可行,yzh,我先试试。
      

  13.   

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;namespace ConsoleApplication4
    {
        public interface IBuilder
        {
            void callA();    }    public class Director
        {        private IBuilder builder;        public Director(IBuilder builder)
            {
                this.builder = builder;
                construct();
            }
            // 将部件partA partB partC最后组成复杂对象
            //这里是将车轮 方向盘和发动机组装成汽车的过程
            public void construct()
            {
                builder.callA();        }    }
        public class Builder1 : IBuilder
        {        public void callA()
            {
                Console.WriteLine(@"It's in builder1.");
            }
        }    public class Builder2 : IBuilder
        {        public void callA()
            {
                Console.WriteLine(@"It's in builder2.");
            }
        }
        class Program
        {
            static void Main()
            {
                Director d1=new Director(new Builder1());
                Director d2=new Director(new Builder2());
                
                Debug.Assert(d1!=null);
                Debug.Assert(d2!=null);
                Console.ReadLine();
            }
        }
    }
    这样可以。
    实现IBuilder的类作为参数传递给Director的构造函数。在调用IBuilder的callA()时IBuilder对象就初始化了。
      

  14.   

    谢谢各位的热心帮助。特别感谢yzh提供的建议。