《.NET程序员面试秘籍》读书笔记

1. 简述 private、 protected、 public、 internal 修饰符的访问权限。

     private :设置类或类的成员为私有,在类的内部才可以访问。有时要访问私有成员时,可通过get和set属性访问器读取或者修改。

     protected :保护成员,该类内部和继承类(子类)中可以访问。(即使子类和基类不在同一个程序集中)

     public : 公共成员,完全公开,没有访问限制。须谨慎使用,滥用会影响类的封装性。 

     internal:  在同一命名空间(程序集)内可以访问。C#默认的类访问修饰符即为internal。(默认的修饰符,可缺省,最常用)

2. 描述sealed修饰符的作用

  用于修饰类、实例方法和属性。sealed修饰类时,该类无法被继承,所以该类也被称为密封类。而abstract类(抽象类)必须被继承才有意义,所以二者是相互排斥,无法共用的。密封方法会重写基类的方法,sealed用于修饰实例被重写的虚方法或虚属性时,表示该方法或属性无法再被重写。

3、举例说明简单工厂模式的作用

       在软件系统中,经常面临“一系列相互依赖对象”的创建工作,为了绕过常规对象的创建方式(即用new创建),利用工厂模式,提供一种“封装机制”来减少功能调用程序和“多系列具体对象创建工作”的耦合性。

《.NET程序员面试秘籍》读书笔记_第1张图片


         简单工厂模式,在工厂类中封装创建对象的实现部分。在应用接口的程序中广泛应用。如下例:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace BaseFactory  
{  
    //声明一个图书接口  
    interface IBook  
    {  
        //声明未实现的图书类型方法bookType()  
        void bookType();  
    }  
    //实现图书接口的A类图书  
    class BookA : IBook  
    {  
        public void bookType()  
        {  
            Console.WriteLine("A类书籍");  
        }  
    }  
    //实现图书接口的B类图书  
    class BookB : IBook  
    {  
        public void bookType()  
        {  
            Console.WriteLine("B类书籍");  
        }  
    }  
    //实例化各类图书对象的工厂  
    class PublishFactory  
    {  
        private IBook bka = new BookA();  //封装创建对象的实部分
        private IBook bkb = new BookB();  
        public IBook getBook(int i)  
        {  
            switch (i)  
            {  
                case 1:  
                    return bka;  
                case 2:  
                    return bkb;  
                default:  
                    return bka;  
            }  
        }  
    }  
    public class BasicFactory  
    {  
        static void Main(string[] args)  
        {  
            PublishFactory pf = new PublishFactory();  
            Console.Write("请输入编号(1或2):");  
            int i = int.Parse(Console.ReadLine());  
            //根据输入的不同参数获得不同的图书对象  
            IBook obj = pf.getBook(i);  
            obj.bookType();  
        }  
    }  
  
}  


接口反映了面向对象编程的一个特性,即多态,多态即通过相同的方法得到不同的实现。如上面的h1.getFav()和h2.getFav();

接口反映了面向对象编程的另个特性,即封装,使用者可以不清楚接口成员实现的细节。

解释: 接口类型obj可以引用不同类的实例,以致相同的bookType方法有不同的表现;使用者只知道传递数字来使用不同接口的不同功能,对内部实现一无所知。实现了更好的封装。

(此例已经够说明了)

运行结果:

        为了处理更复杂的情况,可以将产品再次细分为多个类,用抽象类进行归纳,完成同类产品中共用代码的复用,工厂类也相应地分为多个类,用抽象类进行归纳。如下例:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace LxFactory  
{  
    //声明一个人类接口  
    interface Ihuman  
    {  
        void getFav();        //声明未实现的爱好方法getFav()  
        string getStatus();   //声明未实现的身份状态(孩子,成年人)方法  
    }  
  
    //声明一个抽象类Children,并实现接口的部分方法  
    abstract class Children : Ihuman  
    {  
        protected string _status = "孩子";  
        //实现接口Ihuman中的getStatus()方法  
        public string getStatus()  
        {  
            return _status;  
        }  
        //将接口Ihuman中的getFav()方法映射到抽象方法  
        abstract public void getFav();  
    }  
    //声明一个抽象类Adult,并实现接口的部分方法  
    abstract class Adult : Ihuman  
    {  
        protected string _status = "成年人";  
        //实现接口Ihuman中的getStatus()方法  
        public string getStatus()  
        {  
            return _status;  
        }  
        //将接口Ihuman中的getFav()方法映射到抽象方法  
        abstract public void getFav();  
    }  
  
    //声明男孩类Boy,继承小孩类Children,重写爱好方法getFav()  
    class Boy : Children  
    {  
        public override void getFav()  
        {  
            Console.WriteLine("男孩,我喜欢游戏!");  
        }  
    }  
    //声明女孩类Girl,继承小孩类Children,重写爱好方法getFav()  
    class Girl : Children  
    {  
        public override void getFav()  
        {  
            Console.WriteLine("女孩,我喜欢布娃娃!");  
        }  
    }  
    //声明男人类Man,继承成人类Adult,重写爱好方法getFav()  
    class Man : Adult  
    {  
        public override void getFav()  
        {  
            Console.WriteLine("男人,我喜欢编程!");  
        }  
    }  
    //声明女人类Woman,继承成人类Adult,重写爱好方法getFav()  
    class Woman : Adult  
    {  
        public override void getFav()  
        {  
            Console.WriteLine("女人,我喜欢逛街!");  
        }  
    }  

    //声明一个抽象工厂,分别创建相应类的实例  
    abstract class HumanFactory  
    {  
        protected Ihuman h1 = new Boy();  
        protected Ihuman h2 = new Man();  
        protected Ihuman h3 = new Girl();  
        protected Ihuman h4 = new Woman();  

        //创建一个方法,根据不同输入返回一个接口的引用  
        abstract public Ihuman getHuman(int i);  
    }  
    //声明可以实例化各种类的工厂Factory1,继承类HumanFactory,重写抽象方法getHuman()  
    class Factory1 : HumanFactory  
    {  
        //根据不同输入获得不同对象所属接口的引用  
        public override Ihuman getHuman(int i)  
        {  
            switch (i)  
            {  
                case 1:  
                    return h1;  
                case 2:  
                    return h2;  
                default:  
                    return h1;  
            }  
        }  
    }  
    //声明可以实例化各种类的工厂Factory1,继承类HumanFactory,重写抽象方法getHuman()  
    class Factory2 : HumanFactory  
    {  
        //根据不同输入获得不同对象所属接口的引用  
        public override Ihuman getHuman(int i)  
        {  
            switch (i)  
            {  
                case 1:  
                    return h3;  
                case 2:  
                    return h4;  
                default:  
                    return h3;  
            }  
        }  
    }  
    public class LxFactory  
    {  
        static void Main(string[] args)  
        {  
            //使用工厂1  
            Console.WriteLine("男性中有两种人,请选择编号【1】男孩【2】男人:");  
            int input1 = Int32.Parse(Console.ReadLine());  
            Factory1 f1 = new Factory1();  
            Ihuman h1 = f1.getHuman(input1);  
            h1.getFav();  
            Console.WriteLine("我的身份是:{0}", h1.getStatus());  
  
            //使用工厂2  
            Console.WriteLine("女性中有两种人,请选择编号【1】女孩【2】女人:");  
            int input2 = Int32.Parse(Console.ReadLine());  
            Factory2 f2 = new Factory2();  
            Ihuman h2 = f2.getHuman(input2);  
            h2.getFav();  
            Console.WriteLine("我的身份是:{0}", h2.getStatus());  
        }  
    }  
  
}  

运行结果:

 

4、访问关键字this和base有什么作用

this用于引用类的当前实例(this仅限于构造函数和方法成员中使用,静态成员与实例无关,所以静态成员中不能用this)

base用于派生类访问基类成员(基类被重写的方法和基类的构造函数)

5、简述程序集和应用程序域

 

程序集

一个.NET应用程序可以由多个程序集拼装而成的。程序集,简单来说,就是一个以公共语言运行库(CLR)为宿主的、版本化的、自描述的二进制文件。尽管显示中.NET程序集和以往Win32二进制文件(包括遗留的COM服务对象)的文件扩展名(*.exe或*.dll)完全相同,但是两者的内部构成几乎完全不同。

程序集可以促进代码重用、确定类型边界、可版本化的单元、自描述的、可配置的。

n CIL代码

程序集的核心部分包含CIL代码,这些CIL代码是独立于平台和CPU的中间语言。运行时,程序集内部的CIL代码才被编译成特定平台和CPU的指令。

 

n 类型元数据

元数据完整的描述了程序集内含另行和引用外部类型的格式。

 

n 程序集清单

详细记录了程序集中的每一个模块,构建程序集的版本以及该程序集引用的所有外部程序集。

 

n 可选的嵌入资源

 《.NET程序员面试秘籍》读书笔记_第2张图片

 

      NET平台下,程序集并没有直接加载进进程中(传统的Win32程序是直接承载的)。.NET可执行程序(程序集)承载在进程的一个逻辑分区中,术语称应用程序域(简称AppDomain)。一个进程可以拥有多个应用程序域,应用程序域的全部目的就是提供隔离性,相比较与传统的:(代码, AppDomain.currentDomain)

1.应用程序域是.NET平台操作系统独立性的关键特性。这种逻辑分区将不同操作系统表现加载可执行程序的差异抽象化了。

2.和一个完整的进程相比,应用程序域的CPU和内存占用要小的多。

3.应用程序域为承载的应用程序提供了深度的隔离。一个失败,其他不会失败。

 

单个进程可以承载多个应用程序域,每个程序域都和该进程的其他程序域隔离开来,无法相互访问。在线程启动的时候,CLR将自动创建这个特定的应用程序域(默认应用程序域)。然后根据需要创建其他程序域。

 
《.NET程序员面试秘籍》读书笔记_第3张图片 

 

两边都有mscorlib.dll(程序集),因为所有关键程序集会被CLR自动加载到每一个应用程序域中。

6、简述结构和类的区别

 

  答:(1)结构是值类型(传递的是数据的副本),类是引用类型。所以结构的实例化可以不用new运算符。

(值类型变量一旦超出作用域即被销毁,而应用类型由内存垃圾处理机制完成收集)

(2)结构不能声明无参数的构造函数(默认构造函数)和析构函数。类可以同时有构造函数和析构函数。

(3)结构不支持继承,也无法派生其他的结构或类,(但结构可以实现接口)。而类支持继承。

7、C#函数的参数 修饰符(out、params、ref)的作用

(1)无修饰符,表示按值传递

(2)out修饰,eg. 函数 static void equal(out int a,out int b,out int c)

{ a=2; b=a*100; c=b*100; Console.WriteLine("a、b、c的值分别为:{0}、{1}、{2}",a,b,c);}

     表示按引用 传递参数,实际参数(调用的函数里的参数)传递前不需要赋初值,函数(定义的函数)必须将其赋值。也可以看出out能用于一次调用返回多个值

(3)params修饰,表示形式参数 可以为不确定个数的一组实际参数,这些实际参数必须具有相同的数据类型。

   void text(params string[] txt){}

(4)ref修饰,类似out参数。也表示按引用 传递参数,不过实际参数传递前需要赋初值。


8、如何使用C#的对象构造器

  这是一种新的构造并初始化对象的方法,使用时只需将初始化成员的语句用逗号分隔,位置紧跟在构造函数后面。

 eg. Snake a=new Snake("眼镜蛇"){nm="蟒蛇",Len=10,Wei=20 };

  后面大括号就是对象构造器。。列出了 对象a 的初始化值。  这种方式非常灵活的初始化对象成员,无需定义过多的重载构造函数。


9、如何判断类型实现了某个接口  (as/is关键词)

ClassA a=new ClassA();  

var msg=a as ITest;    

 class  ClassA:ITest{ 类体}

if(msg==null)

{"未实现"}

 else {"实现了"}

或者用 a is ITest


10、数组列表和数组有什么区别

非常相似,但是数组列表(即ArrayList类, 位于System.Collection下)的容量可以动态变化;有点类似StringBuilder类。。

ArrayList.Add(); ArrayList.Insert(); ArrayList.AddRange();-----

  数组(即Array类,位于System下,)在初始化时要指定容量,并且指定后无法更改。



转载于:https://www.cnblogs.com/peterYong/p/6556617.html

你可能感兴趣的:(面试,c#,操作系统)