none
求“技术资源库”中关于c#方法示例的一个问题 RRS feed

  • 问题

  • http://msdn.microsoft.com/zh-cn/library/ms173114.aspx中技术资源库”中关于c#方法示例,划线的部分代码如下

     abstract class Motorcycle
    {
       
    // Anyone can call this.
        public void StartEngine() {/* Method statements here */ }

       
    // Only derived classes can call this.
        protected void AddGas(int gallons) { /* Method statements here */
    }

       
    // Derived classes can override the base class implementation.
        public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

       
    // Derived classes must implement this.
        public abstract double GetTopSpeed();
    }

    在紧接着的派生类调用这个方法却报错是乍回事呢捏?

    class TestMotorcycle : Motorcycle
    {

        public override double GetTopSpeed()
        {
            return 108.4;
        }

        static void Main()
        {

            TestMotorcycle moto = new TestMotorcycle();

            moto.StartEngine();
            moto.AddGas(15);
            moto.Drive(5, 20);
            double speed = moto.GetTopSpeed();
            Console.WriteLine("My top speed is {0}", speed);           
        }
    }


    编译器报这个错误

    错误 1 “Class01Method.Program.Motorcycle.AddGas(int)”不可访问,因为它受保护级别限制 

    怎么微软的示例都运行不了啊?

    2011年3月1日 1:12

答案

  • 您好,我在vs2008和vs2010中都测试了微软的例子。没有问题!您是不是做了什么改动?

    说实在的当看到您贴的信息我还以为vs2010做了修改。我个人更高兴看到不能运行的结果。因为这样才体现了封装性。

    虽然TestMotorcycle是Motorcycle的子类,但Main是个静态的方法,我们在其中new了一个TestMotorcycle。

    既然new了一个TestMotorcycle,我们通常就会把TestMotorcycle看成一个黑盒子,那么对于黑盒子来说应该只有public方法能被调用,其他的保护方法应该都不能被调用。然而c#编译器对继承类作了简单的处理,都一致认为可调用protected方法。

    2011年3月1日 2:24
    版主
  • 1、派生类能继承基类的protected方法,也就是说它自己也拥有了一个一样的protected方法。那么protected方法就只能在继承类中访问,这是面向对象的语言规则规定的。这个概念与new无关,是两个概念。new是先把东西创建出来,然后才是这个东西的哪些部分(属性或方法)能被访问。 想防止new,只需要将构造函数声明为private

    2、是的。但在protected后面添加internal表示可以由继承类访问也可以由同一个程序集内的类访问。加了internal就扩大了它的访问范围。在同一个程序集内就如同改为public。

    • 已建议为答案 QLoveQ 2011年3月1日 3:39
    • 已标记为答案 wavetekgroup 2011年3月1日 3:55
    2011年3月1日 3:28
    版主
  • 感谢楼主的回复,谢谢。

    你深入的剖析了关键字protected和internal的关系,和应用范围,但是你的最后一句话更严谨的说应该是“另外如果单独使用 internal则表示同一个程序集中的任何类和对象 都能访问。”吧(不光是类还应包括对象吧),对不楼主?


    wavetekgroup
    哈,不用这么繁琐。对象是类实例化的结果。是运行时的表现。通常我们讨论可见修饰符时不会用对象这个称呼。就如同,我们不会在讨论中使用派生对象而是派生类。
    2011年3月2日 3:51
    版主

全部回复

  • 这个是为了说明 这个是受保护的方法 只能在派生类中调用。

     


    family as water
    2011年3月1日 2:07
  • Hi,

    欢迎到MSDN论坛。

    我用您的代码测试的时候,发现并没有报错,按照一般来讲,只要子类能点出来的方法属性,说明就有访问权限,运行编译肯定是没有错误的。

    能详细说下运行环境吗?

    Best Regards,

    Rocky

     

    2011年3月1日 2:18
  • 您好,我在vs2008和vs2010中都测试了微软的例子。没有问题!您是不是做了什么改动?

    说实在的当看到您贴的信息我还以为vs2010做了修改。我个人更高兴看到不能运行的结果。因为这样才体现了封装性。

    虽然TestMotorcycle是Motorcycle的子类,但Main是个静态的方法,我们在其中new了一个TestMotorcycle。

    既然new了一个TestMotorcycle,我们通常就会把TestMotorcycle看成一个黑盒子,那么对于黑盒子来说应该只有public方法能被调用,其他的保护方法应该都不能被调用。然而c#编译器对继承类作了简单的处理,都一致认为可调用protected方法。

    2011年3月1日 2:24
    版主
  • 谢谢,你的关注,

    Rocky

    我用的是vs2010,将上述代码重新复制到一个新建的控制台应用程序里,报这个错,我查看了moto对象调用方法,点点提示框里没有AddGas方法,除非添加internal关键字才能调用此方法,这是乍回事?


    wavetekgroup
    2011年3月1日 2:28
  • 这是我的全部代码,AddGas方法不能调用,错在哪呢?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace Class01Method
    {
        class Program
        {
            abstract class Motorcycle
            {
                // Anyone can call this.
                public void StartEngine() {/* Method statements here */ }

                // Only derived classes can call this.
                protected void AddGas(int gallons) { /* Method statements here */ }

                // Derived classes can override the base class implementation.
                public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

                // Derived classes must implement this.
                public abstract double GetTopSpeed();
            }

            class TestMotorcycle : Motorcycle
            {

                public override double GetTopSpeed()
                {
                    return 108.4;
                }

                public override int Drive(int miles, int speed)
                {
                    return miles * speed;
                }
            }

            static void Main(string[] args)
            {
                TestMotorcycle moto = new TestMotorcycle();

                moto.StartEngine();
                moto.AddGas(15);
                moto.Drive(5, 20);
                double speed = moto.GetTopSpeed();
                Console.WriteLine("My top speed is {0}", speed);

                Console.ReadKey();
            }
        }
    }


    wavetekgroup
    2011年3月1日 2:44
  • 把Main移到TestMotorcycle里, 并删除class Program

    class TestMotorcycle : Motorcycle
            {

                public override double GetTopSpeed()
                {
                    return 108.4;
                }

                public override int Drive(int miles, int speed)
                {
                    return miles * speed;
                }

                static void Main(string[] args)
            {
                TestMotorcycle moto = new TestMotorcycle();

                moto.StartEngine();
                moto.AddGas(15);
                moto.Drive(5, 20);
                double speed = moto.GetTopSpeed();
                Console.WriteLine("My top speed is {0}", speed);

                Console.ReadKey();
            }


             }

     

    namespace Class01Method
    {
            abstract class Motorcycle
            {}

            class TestMotorcycle : Motorcycle
            {}

    }

    2011年3月1日 2:46
    版主
  • 哦,谢谢楼主的指点,再请教一下是派生类引用的protected基类方法只能在派生类内部的入口函数中使用吗?为啥,不能在派生类以外的入口函数中调用呢?不是也在派生类外的入口函数中new了派生类了吗?

    我这样理解是不是因为protected只能由类或派生类中的代码访问,所以必须把入口函数放在派生类中?这也是我上面提到在外部入口函数中调用这个方法时,在protected后面添加

    关键字internal就可以调用的原因呢?


    wavetekgroup
    2011年3月1日 3:13
  • 1、派生类能继承基类的protected方法,也就是说它自己也拥有了一个一样的protected方法。那么protected方法就只能在继承类中访问,这是面向对象的语言规则规定的。这个概念与new无关,是两个概念。new是先把东西创建出来,然后才是这个东西的哪些部分(属性或方法)能被访问。 想防止new,只需要将构造函数声明为private

    2、是的。但在protected后面添加internal表示可以由继承类访问也可以由同一个程序集内的类访问。加了internal就扩大了它的访问范围。在同一个程序集内就如同改为public。

    • 已建议为答案 QLoveQ 2011年3月1日 3:39
    • 已标记为答案 wavetekgroup 2011年3月1日 3:55
    2011年3月1日 3:28
    版主
  • 谢谢,楼主你回答的概念十分清晰准确,感谢非常感谢。

    接着上面的问题,“正如你所描述,派生类能继承基类的protected方法,也就是说它自己也拥有了一个一样的protected方法。那么protected方法就只能在继承类中访问,这是面向对象的语言规则规定的。”那么是不是可以理解为正是i因为protected方法只能由派生类中的代码访问(请注意,即派生类程序块内部代码访问),也就是更引深为只能在派生类程序块内部的派生类对象使用,这也就是为啥派生类对象必须在派生类的程序块里面才能调用派生类方法的根本原因了?因此超出派生类之外的程序块中的派生类对象,也就无法访问派生类里面的protected方法了?进而如果基类方法protected internal了,正如你所说internal扩大了范围如同在程序集部public,但是是不是也只能通过不在派生类程序块内部的派生类对象调用,而不能通过其他对象调用,如:基类对象?


    wavetekgroup
    2011年3月1日 4:38
  • 1、这也就是为啥派生类对象必须在派生类的程序块里面才能调用派生类方法的根本原因了?

    答:是的。

    2、因此超出派生类之外的程序块中的派生 类对象,也就无法访问派生类里面的protected方法了?

    答:应该是:超出派生类之外的程序块中的其它 类,也就无法访问派生类里面的protected方法。

    3、是不是也只能通过不在派生类程序块内部的派生类对象调用,而不能通过其他对象调用,如:基类对象?

    答:我理解为您想了解protected internal的规则。通常会认为protected internal是protected and internal,而实际上是protected or internal。也就是说如果是派生类 或是同一个程序集的任何类 都能访问。包括基类,但通常不会在基类中调用子类的方法。这不符合设计原则。但我见过微软的asp.net框架调用过子类的静态方法。另外如果单独使用 internal则表示同一个程序集的任何类 都能访问。

    • 已建议为答案 QLoveQ 2011年3月1日 7:15
    2011年3月1日 5:18
    版主
  • 感谢楼主的回复,谢谢。

    你深入的剖析了关键字protected和internal的关系,和应用范围,但是你的最后一句话更严谨的说应该是“另外如果单独使用 internal则表示同一个程序集中的任何类和对象 都能访问。”吧(不光是类还应包括对象吧),对不楼主?


    wavetekgroup
    2011年3月1日 14:56
  • 感谢楼主的回复,谢谢。

    你深入的剖析了关键字protected和internal的关系,和应用范围,但是你的最后一句话更严谨的说应该是“另外如果单独使用 internal则表示同一个程序集中的任何类和对象 都能访问。”吧(不光是类还应包括对象吧),对不楼主?


    wavetekgroup
    哈,不用这么繁琐。对象是类实例化的结果。是运行时的表现。通常我们讨论可见修饰符时不会用对象这个称呼。就如同,我们不会在讨论中使用派生对象而是派生类。
    2011年3月2日 3:51
    版主