zoukankan      html  css  js  c++  java
  • 转:.NET 面试题汇总(二)

     原文地址:http://www.cnblogs.com/jearay/p/7722223.html

    正文

    本次给大家介绍的是我收集以及自己个人保存一些.NET面试题第二篇

    第一篇文章请到这里:转:.NET 面试题汇总(一)

    简介

    • 此次包含的不止是.NET知识,也包含少许前端知识以及.net面试时所涉及的种种考点,希望能给找工作的同学们哪怕一点点帮助。

    在此提醒下,本文适合:

    • 刚毕业的萌新
    • 工作不久换工作的
    • 大牛可忽略啦

    1.接口

    文章引用:http://www.cnblogs.com/jiajiayuan/archive/2011/09/16/2178462.html

    ①.接口的特性:

    1. 接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:
    • 当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。
    • 当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的。
    1. 接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员。
    2. 接口成员是自动公开的,且不能包含任何访问修饰符。
    3. 接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类。

    ②为什么不能指定接口中方法的修饰符?

    接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。它们默认为公有方法。

    interface IProgram
        {
            void Fun();
        }
        class Program:IProgram
        {
             //显式实现接口成员
            void IProgram.Fun()
            {
                Console.WriteLine("I am Fun.");
            }
            staticvoid Main(string[] args)
            {
                IProgram p =new Program();  //声明一个接口实例,但不是对接口进行实例化
                p.Fun();
                Console.Read();
            }
        }

    ③实现接口可以显式实现和隐式实现,那么这两种实现到底有什么优缺点呢?

    一般情况,当类或者结构要实现的是单个接口,可以使用隐式实现。
    如果类或者结构继承了多个接口且接口中具有相同名称成员时,就要用到显式实现,当显式实现方式存在时,隐式实现方式就失效了。

    interface IProgram
        {
            void Fun();
        }
        interface IAProgram
        {
            void Fun();
        }
        class Program : IProgram, IAProgram
        {
            void IProgram.Fun()  //显式实现接口IProgram
            {
                Console.WriteLine("I am IProgram Fun.");
            }
            void IAProgram.Fun()  //显式实现接口IAProgram
            {
                Console.WriteLine("I am IAProgram Fun.");
            }
            //public void Fun()   //隐式实现接口
            //{
            //    Console.WriteLine("I am Program Fun.");
            //}
            staticvoid Main(string[] args)
            {
                //IProgram p = new Program();
                //p.Fun();
                //IAProgram ap = new Program();
                //ap.Fun();
                Program pro =new Program();
                ((IProgram)pro).Fun();
                ((IAProgram)pro).Fun();
                Console.Read();
            }
        }

    ④接口的继承:

    接口继承和类继承不同

    1. 首先,类继承不仅是说明继承,而且也是实现继承;而接口继承只是说明继承。
      也就是说,派生类可以继承基类的方法实现,而派生的接口只继承了父接口的成员方法说明,而没有继承父接口的实现;
    2. 其次,C#中类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口。
      接口可以从零或多个接口中继承。从多个接口中继承时,用":"后跟被继承的接口名字,多个接口名之间用","分割。
      被继承的接口应该是可以访问得到的,比如从private 类型或internal 类型的接口中继承就是不允许的。
      接口不允许直接或间接地从自身继承。和类的继承相似,接口的继承也形成接口之间的层次结构。
    interface IProgram
        {
            void Fun();
        }
        interface IAProgram:IProgram
        {
            
        }
        class Program :  IAProgram
        {
            void IProgram.Fun()
            {
                Console.WriteLine("I am IProgram Fun.");
            }
            static void Main(string[] args)
            {
                Program pro =new Program();
                ((IAProgram)pro).Fun();
                Console.Read();
            }
        }

    ⑤接口的覆盖:

    由于接口的实现没有方法体,抽象方法也没有方法体,那么当我们在接口的实现方法里调用抽象方法时,会如何执行呢?

    interface IProgram
        {
            void Fun();
        }
        abstract class AProgram : IProgram
        {
            public abstract void AFun();
            void IProgram.Fun()
            {
                AFun();
            }
        }
        class Program:AProgram
        {
            public override void AFun()
            {
                Console.WriteLine("I am AProgram.");
            }
            static void Main(string[] args)
            {
                IProgram pro =new Program();
                pro.Fun();
                Console.Read();
            }
        }
    //结果:I am Aprogram.

    通过断点,可以看到,当执行pro.Fun();时,首先会跳到接口的实现方法里,然后去调用抽象函数的实现方法,当抽象函数的方法实现后,再回到接口的实现方法,直到执行完成

    当我们在实现接口的方法里调用虚函数呢?

    interface IProgram
        {
            void Fun();
        }
        class AProgram : IProgram
        {
            public virtual void AFun()    //注意这里是虚函数
            {
                Console.WriteLine("I am virtual AFun.");
            }
            void IProgram.Fun()
            {
                AFun();
            }
        }
        class Program:AProgram
        {
            public override void AFun()  //这里是Override重写
            {
                Console.WriteLine("I am override AFun.");
            }
            static void Main(string[] args)
            {
                IProgram pro =new Program();
                pro.Fun();
                Console.Read();
            }
        }

    这时,我们发现,执行的顺序和上一个例子是相同的。所以结果为:I am override AFun.
    由此,我们可以继续联想,当我们把override关键字,换成new呢?是不是也是同样的结果,还是和我们以前讲的例子一样,是隐藏呢?

    我们把上面的例子进行改进:

    interface IProgram
        {
            void Fun();
        }
        class AProgram : IProgram
        {
            public virtual void AFun()
            {
                Console.WriteLine("I am virtual AFun.");
            }
            void IProgram.Fun()
            {
                AFun();
            }
        }
        class Program:AProgram
        {
            public new void AFun()
            {
                Console.WriteLine("I am new AFun.");
            }
            static void Main(string[] args)
            {
                Program pro =new Program();
                ((IProgram)pro).Fun();
                pro.AFun();
                Console.Read();
            }
        }
        

    结果为:

    I am virtual AFun.
    I am new AFun.

    由于前面已经讲过了==,这里不在对此进行分析,由此我们可知使用New关键字是对其进行隐藏,当对接口实现的方法里调用的是虚方法时,和类的执行过程是一样的。

    ⑥接口和抽象类的区别

    1. 接口用于规范,抽象类用于共性。
    2. 接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。
    3. 抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。
    4. 抽象类可以提供某些方法的部分实现,接口不可以。
    5. 抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。
    6. 在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。
    7. 接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。
    8. 此外接口不能包含字段、构造函数、析构函数、静态成员或常量。

    ⑦C#中的接口和类有什么异同

    1. 不能直接实例化接口。
    2. 接口不包含方法的实现。
    3. 接口可以实现多继承,而类只能是单继承。
    4. 类定义可在不同的源文件之间进行拆分。

    1. 接口、类和结构可从多个接口继承。
    2. 接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
    3. 接口可以包含事件、索引器、方法和属性。
    4. 一个类可以实现多个接口。

    2.您在什么情况下会用到虚方法或抽象类,接口?

    1. 如果某个方法可能性在派生类中会被重写。这时就将该方法写为虚方法。
    2. 抽象类:是一个类型,与派生类之间的关系是一个“ISA”的关系。用来做基类,抽象类不能创建对象,类中包括抽象方法和实例方法。
    3. 接口:是设计一个规范,描述了Can do ;与实现类之间是中”LINE A 的关系,C#中接口不能包含字段访问修饰符。

    3.重载(Overload )和覆写(Override)的区别

    简述:简单的说,一个是同一个函数的几种形式,一个是重写父类函数。

    重载:当类包含两个名称相同但签名不同(方法名相同,参数列表不相同)的方法时发生方法重载。用方法重载来提供在语义上完成相同而功能不同的方法。

    覆写:在类的继承中使用,通过覆写子类方法可以改变父类虚方法的实现。

    区别:

    1. 方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系。
    2. 覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。
    3. 覆盖要求参数列表相同;重载要求参数列表不同。
    4. 覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。

    4.值类型和引用类型的区别?写出C#的样例代码。

    简述:值类型包括简单类型、结构体类型和枚举类型,引用类型包括自定义类、数组、接口、委托等

    1. 赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对象的引用,而不复制对象本身。
    2. 派生:值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
    3. null:与引用类型不同,值类型不可能包含 null 值。然而,可空类型功能允许将 null 赋给值类型。
    4. 每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。
      值类型主要由两类组成:结构、枚举

      ①. 结构分为以下几类:Numeric(数值)类型、整型、浮点型、decimal、bool、用户定义的结构。

      ②. 引用类型的变量又称为对象,可存储对实际数据的引用。声明引用类型的关键字:class、interface、delegate、内置引用类型: object、string

    5. 值类型存贮在中,而引用类型存贮在动态的堆中,栈是先进先出的有系统管理的空间,而堆是由应用程序控制的可随时申请和释放该空间,在Donnet中一般情况下有垃圾收集器处理,他们的不同导致在编程上的不同。
      例:

    using System;
    using System.Text;
    class EventDel
    {
        static void Main(string[] args)
        {
            StringBuilder a=new StringBuilder();//将StringBuilder的一个首地址传给a
            StringBuilder b=a;                  //将StringBuilder的一个首地址传给b
            b.Append("mxh");
            Console.WriteLine(a);
            a=null;
            Console.WriteLine(b);
        }
    }

    "a=null"的意思是:a的引用置为空但此时StringBuilder的堆空间并没有被释放,因此在此之后,输出b时,仍然可以输出mxh

    输出结果:
    mxh
    mxh

    5.委托和事件简述

    参考资料 :
    C# 知识回顾 - 委托 delegate

    C# 知识回顾 - 委托 delegate (续)

    事件是不是一种委托?

    委托是一种安全的函数指针,事件是一种消息机制

    委托与事件是什么关系?为什么要使用委托

    委托提供了封装方法的方式,事件是某动作已发生的说明,事件是建立于委托之上的。

    程序运行时同一个委托能够用来调用不同的方法,只要改变它的引用方法即可,因此委托调节器用的方法不是在编译时决定的,而是在运行时确定的.

    6.Session,ViewState,Application,cookie的区别?

    1. Session:用于保持状态的基于 Web 服务器的方法。Session 允许通过将对象存储在Web 服务器的内存中在整个用户会话过程中保持任何对象。主要用于保持代码隐藏类中对象的状态。为每个用户创建的,用于存储单个用户,因为他是相对每个用户的.所以可能来取得在线人数等。
    2. ViewState:主要用于保持 Web 页上控件的状态。当 Web 页上的控件被绑定到代码隐藏类中的对象。
    3. Application 用于存储所有用户都可视的信息.所以它存储的是要让所有用户共享的一些信息.如总访问数等Cache,页面缓存。
    4. Cookie:通常我们都把它放在客户端,也可以存储在服务器端。主要用它存储用户的个性设制,和登陆信息。

    7.Application,Session,Cookie,ViewState和Cache生命周期

    在ASP.NET中,有很多种保存信息的内置对象,如:Application,Session,Cookie,ViewState和Cache等。下面分别介绍它们的用法和区别。

    ①.Application对象

    Application用于保存所有用户的公共的数据信息,如果使用Application对象,一个需要考虑的问题是任何写操作都要在Application_OnStart事件(global.asax)中完成.尽管使用Application.Lock和Applicaiton.Unlock方法来避免写操作的同步,但是它串行化了对Application对象的请求,当网站访问量大的时候会产生严重的性能瓶颈.因此最好不要用此对象保存大的数据集合. 下面我们做个在线用户统计的例子来说明这个问题:

    Global.asax类
       代码
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Web;
    using System.Web.SessionState;
    using System.IO;
        /// Global 的摘要说明。
         public class Global : System.Web.HttpApplication
        {
            /// 必需的设计器变量。
            private System.ComponentModel.IContainer components = null;
    
            private FileStream fileStream;
            private StreamReader reader;//读字符流
            private StreamWriter writer;//写字符流
            
            public Global()
            {
                InitializeComponent();
            }    
    
            protected void Application_Start(Object sender, EventArgs e)
            {
                Application["CurrentGuests"]=0;//初始花为0;
                fileStream = File.Open(Server.MapPath("counts.text"),FileMode.OpenOrCreate);//文件不存在,创建文件
                reader = new StreamReader(fileStream);//要读取的完整路径
                Application["AllGuests"] = Convert.ToInt32(reader.ReadLine()); //从当前流中读取一行字符并将数据作为字符串返回
                reader.Close();//关闭流
            }
     
            protected void Session_Start(Object sender, EventArgs e)//当用户访问网站时,在线用户+1,总访问数+1
            {
                Application.Lock();//同步,避免同时写入
                
                Application["CurrentGuests"] =(int)Application["CurrentGuests"]+ 1;//总在线用户数
                Application["AllGuests"] =(int)Application["AllGuests"]+ 1;//访问网站的总用户数
                fileStream = new FileStream(Server.MapPath("counts.text"),FileMode.OpenOrCreate,FileAccess.ReadWrite);//
                writer = new StreamWriter(fileStream);//实现一个写入流,使其以一种特定的编码向流中写入字符
                writer.WriteLine(Application["AllGuests"].ToString());//把访问网站的总用户数再次写入到文件
                writer.Close();//关闭写入流
    
                Application.UnLock();//同步结束
            }
            protected void Session_End(Object sender, EventArgs e)//当前用户退出网站时,在线用户数量-1,
            {
                Application.Lock();
                Application["CurrentGuests"] =(int)Application["CurrentGuests"] - 1;//总在线用户数量-1
                Application.UnLock();    
            }
        (2) WebForm1.aspx
        private void Page_Load(object sender, System.EventArgs e)
            {
                this.Label1.Text = "正在访问站点的用户数:" + Application["CurrentGuests"].ToString();    
                this.Label2.Text ="访问过站点的总用户数:" + Application["AllGuests"].ToString();
            }

    ②.Session对象

    Session用于保存每个用户的专用信息.每个客户端用户访问时,服务器都为每个用户分配一个唯一的会话ID(Session ID) . 她的生存期是用户持续请求时间再加上一段时间(一般是20分钟左右).Session中的信息保存在Web服务器内容中,保存的数据量可大可小.当Session超时或被关闭时将自动释放保存的数据信息.由于用户停止使用应用程序后它仍然在内存中保持一段时间,因此使用Session对象使保存用户数据的方法效率很低.对于小量的数据,使用Session对象保存还是一个不错的选择.使用Session对象保存信息的代码如下:

    //存放信息
    Session["key"]="value"
    //读取数据
    string UserName=Session["key"].ToString();

    ③.Cookie对象

    Cookie用于保存客户浏览器请求服务器页面的请求信息,程序员也可以用它存放非敏感性的用户信息,信息保存的时间可以根据需要设置.如果没有设置Cookie失效日期,它们仅保存到关闭浏览器程序为止.如果将Cookie对象的Expires属性设置为Minvalue,则表示Cookie永远不会过期.Cookie存储的数据量很受限制,大多数浏览器支持最大容量为4K,因此不要用来保存数据集及其他大量数据.由于并非所有的浏览器都支持Cookie,并且数据信息是以明文文本的形式保存在客户端的计算机中,因此最好不要保存敏感的,未加密的数据,否则会影响网站的安全性.使用Cookie对象保存的代码如下:

    //存放信息
    Response.Cookies["key"].Value="value";
    //读取信息
    string UserID=Response.Cookies["key"].Value;

    ④.ViewState对象

    ViewState 常用于保存单个用户的状态信息,有效期等于页面的生存期。跟隐藏控件相似。viewstate是在本页面之内各函数间进行传值的 , 至于为什么要使用这种方法是因为在一个事件发生之后 , 页面可能会刷新 , 如果定义全局变量会被清零 , 所以要使用viewstate. ViewState容器可以保持大量的数据,但是必须谨慎使用,因为过多使用会影响应用程序的性能。所有Web服务器控件都使用ViewState在页面回发期音保存自己的状态信息。如果某个控件不需要在回发期间保存状态信息,最好关闭该对象的ViewState,避免不必要的资源浪费。通过给@Page指令添加“EnableViewState=false”属性可以禁止整个页面的ViewState。使用ViewState对象保存信息的代码如下。

      //存放信息
      ViewState["key"]="value";
      //读取信息
      string NameID=ViewState["nameID"].ToString();

    ⑤.Cache对象

    Cache对象用于在HTTP请求间保存页面或数据。该对象的使用可以极大地提高整个应用程序的效率。常用于将频繁访问的大量服务器资源存储在内存中,当用户发出相同的请求后服务器不再次处理而是将Cache中保存的信息返回给用户,节省了服务器处理请求的时间。其生存期依赖于该应用程序的生存期。当重新启动应用程序时,将重新创建其Cache对象的实例。使用Cache对象保存信息的代码如下。

      //存放信息
      Cache["nameID"]="0001";
      //存放信息
      Cache.Insert("nameID","0001"1);
      //读取信息
      string NameID=Cache["nameID"].ToString();

    ⑥.隐藏域

    Hidden控件是属于HTML类型的服务器控件,使用此控件可以实现隐藏域的功能。其实此控件和其它服务器控件的使用没有太大区别,只是它不会在用户端的浏览器中显示,始终处于隐藏状态。但是每次页面提交的时候,此控件和其它服务器控件一同提交到服务器端,因此在服务器端可以使用Value属性获取或保存一些数据信息。使用Hidden控件保存信息的代码如下。

     //存放信息
      Hidden.Value="0001";
      //获取信息
      string NameID=Hidden.Value;

    ⑦.查询字符串

    查询字符串的方式是将要传递的值连接在URL后面,然后通过Response.Redirect方法实现客户端的重定向。这种方式可以实现在两个页面之间传递信息。由于URL的长度有一定的限制,因此不能传递太大的信息,加外安全性也不是很好。
    传递信息如下。问号后面格式 key1=value1&key2=value2

    Response.Redirect("List.aspx?nameID=0001&gradeID=002");
      //执行上面的语句后在IE地址栏显示的URL的代码如下。
      http://localhost/List.aspx?nameID=0001&grade=002
      //当跳转到List.aspx后,可以通过以下代码获得所传递的信息。
      string NameID.GradeID;

    8.ajax原理

    简述: Ajax的原理就是:通过javascript的方式,将前台数据通过xmlhttp对象传递到后台,后台在接收到请求后,将需要的结果,再传回到前台,这样就可以实现不需要页面的回发,页是数据实现来回传递,从页实现无刷新。

    Ajax的原理简单来说,实际上就是通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
    这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。

    总结:我们可以看出,XMLHttpRequest对象完全用来向服务器发出一个请求的,它的作用也局限于此,但它的作用是整个ajax实现的关键,我们可以把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,可以是Html,可以是Javascript代码,也可以只是一个字符串。这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,客户端在异步获取这个结果后,不是直接显示在页面,而是先由javascript来处理,然后再显示在页面。

    9.请叙述属性与索引器的区别

    属性索引器
    通过名称标识 通过签名标识
    通过简单名称或成员访问来访问 通过元素访问来访问
    可以为静态成员或实例成员 必须为实例成员
    属性的get访问器没有参数 索引器的get访问器具有与索引器相同的形参表
    属性的set访问器包含隐式value参数器 除了value参数外,索引的 set 访问器还具有与索引器相同的形参表

    10.String类与StringBuilder类有什么区别?为啥在.Net类库中要同时存在这2个类?

    如果要操作一个不断增长的字符串,尽量不用String类,改用StringBuilder类

    String类原理:String类是一种传统的修改字符串的方式,它确实可以完成把一个字符串添加到另一个字符串上的工作没错,但是在.NET框架下,这个操作实在是划不来。因为系统先是把两个字符串写入内存,接着删除原来的String对象,然后创建一个String对象,并读取内存中的数据赋给该对象。这一来二去的,耗了不少时间。

    StringBulider原理:而使用 System.Text命名空间下面的StringBuilder类就不是这样了,它提供的Append方法,能够在已有对象的原地进行字符串的修改,简单而且直接。

    提醒:一般情况下觉察不到这二者效率的差异,但如果你要对某个字符串进行大量的添加操作,那么StringBuilder类所耗费的时间和 String类简直不是一个数量级的

    11.浅谈C#中的枚举

    枚举类型是一种的值类型,它用于声明一组命名的常数。

    ①.枚举的声明:枚举声明用于声明新的枚举类型。

     访问修辞符 enum 枚举名:基础类型
        {
            枚举成员
        }

    基础类型必须能够表示该枚举中定义的所有枚举数值。枚举声明可以显式地声明 byte、sbyte、short、ushort、int、uint、long 或 ulong 类型作为对应的基础类型。没有显式地声明基础类型的枚举声明意味着所对应的基础类型是 int。

    ②.枚举成员

    枚举成员是该枚举类型的命名常数。任意两个枚举成员不能具有相同的名称。每个枚举成员均具有相关联的常数值。此值的类型就是枚举的基础类型。每个枚举成员的常数值必须在该枚举的基础类型的范围之内。

        public enum TimeofDay:uint
            {
                Morning=-3,
                Afternoon=-2,
                Evening=-1
             }  

    产生编译时错误,原因是常数值 -1、-2 和 –3 不在基础整型 uint 的范围内。

    ③.枚举成员默认值

    在枚举类型中声明的第一个枚举成员它的默值为零。
    以后的枚举成员值是将前一个枚举成员(按照文本顺序)的值加 1 得到的。这样增加后的值必须在该基础类型可表示的值的范围内;否则,会出现编译时错误。

        示例:
            public enum TimeofDay:uint
            {
                Morning,
                Afternoon,
                Evening
             }   

    Morning的值为0,Afternoon的值为1,Evening的值为2。

    ④.为枚举成员显示赋值

    允许多个枚举成员有相同的值。没有显示赋值的枚举成员的值,总是前一个枚举成员的值+1

      public enum Number
            {
                a=1,
                b,
                c=1,
                d
            }

    b的值为2,d的值为2.
    注意:以上枚举值都不能超过它的基础类型范围。否则会报错.

    ⑤.枚举类型与基础类型的转换

    基础类型不能隐式转换为枚举类型; 枚举类型也不能隐式转换为基础类型

    public enum Number
        {
            a,
            b,
            c,
            d
        }
    
        class Test
        {
            public static void Main()
            {
                int i=Number.a;//错误,要强制类型转换(int)Number.a
                Number n;
                n=2            //错误,要强制类型转换(Number)2
            }
        }

    ⑥.System.Enum类型

    1. System.Enum 类型是所有枚举类型的抽象基类,并且从 System.Enum 继承的成员在任何枚举类型中都可用。
    2. System.Enum 本身不是枚举类型。相反,它是一个类类型,所有枚举类型都是从它派生的。
    3. System.Enum 从类型 System.ValueType派生

    ⑦.使用枚举类型

     using System;
            public enum TimeofDay
            {
                 Morning,
                 Afternoon,
                 Evening
            }   
            class Test 
            {
                 static void WriteGreeting(TimeofDay timeofDay)
                 {            
                      switch(timeofDay)
                      {
                           case TimeofDay.Morning:
                                Console.WriteLine("good morning");
                                break;
                           case TimeofDay.Afternoon:
                                Console.WriteLine("good afternoon");
                                break;
                           case TimeofDay.Evening:
                                Console.WriteLine("good evening");
                                break;
                      }
                 }
                 static void Main() 
                 {
                      WriteGreeting(TimeofDay.Morning); 
                      WriteGreeting(TimeofDay.Evening);
                      WriteGreeting(TimeofDay.Afternoon);
                 }
            }    

    12.C#的New关键字的几种用法

    ①.new运算符:用于创建对象和调用构造函数。

    • 用于创建对象和调用构造函数 例:Class_Test MyClass=new Class_Test();
    • 也用于为值类型调用默认的构造函数
    例:int myInt=new int();

    myInt初始化为0,它是int类型的默认值。该语句的效果等同于:intmyInt=0;

    • 不能重载new运算符;
    • 如果new运算符分配内存失败,则它将引发OutOfMemoryException异常。

    ②.new修饰符

    使用new修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用new修饰符修饰它。

    请看下面的类:

    public class MyClass 
    { 
    public int x; 
    public void Invoke(){} 
    }

    在派生类中用Invoke名称声明成员会隐藏基类中的Invoke方法,即:

    public class MyDerivedC:MyClass 
    { 
    new public void Invoke(){} 
    }

    但是,因为字段x不是通过类似名隐藏的,所以不会影响该字段。

    通过继承隐藏名称采用下列形式之一:

    1.引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。

    2.引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。

    3.引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。

    4.在同一成员上同时使用new和override是错误的。

    注意:在不隐藏继承成员的声明中使用new修饰符将生成警告。

    示例:在该例中,嵌套类MyClass隐藏了基类中具有相同名称的类。该例不仅说明了如何使用完全限定名访问隐藏类成员,同时也说明了如何使用new修饰符消除警告消息。

    using System; 
    public class MyBaseC
    {
    public class MyClass
    {
    public int x=200;
    public int y;
    }
    }
    
    public class MyDerivedC:MyBaseC
    {
    new public class MyClass //nestedtypehidingthebasetypemembers
    {
    public int x=100;
    public int y;
    public int z;
    }
    public static void Main()
    {
    //Creating object from the overlapping class:
    MyClass S1=new MyClass();
    
    //Creating object from the hidden class:
    MyBaseC.MyClass S2=new MyBaseC.MyClass();
    
    Console.WriteLine(S1.x);
    Console.WriteLine(S2.x);
    }

    输出:
    100
    200

    ③.new约束:用于在泛型声明中约束可能用作类型参数的参数的类型。

  • 相关阅读:
    Shell编程—用户输入
    Shell编程—结构化命令
    Shell编程—基础脚本
    跳表
    分布式项目——电商秒杀
    Dubbo详解
    Kafka工作流程
    Kafka内部实现原理
    Zk实现分布式锁
    Leetcode::Pathsum & Pathsum II
  • 原文地址:https://www.cnblogs.com/jearay/p/7722357.html
Copyright © 2011-2022 走看看