C#的基础知识问答

    技术2022-05-11  1

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

    答:没有标明访问级别的就是private。private:私有成员,只能在类的内部才可以访问。protected: 保护成员,只能从所在类和所在类派生的子类进行访问public: 公共成员,不限制对该类的访问。internal: 访问仅限于当前程序集(Assembly)。internal protected: 访问仅限于程序集(Assembly)和程序集(Assembly)所属的类派生的类型。

    2.什么是命名空间?它的作用是什么?

    答:命名空间是一组保持唯一的名称。命名空间用于声明一个范围,此命名空间范围允许您组织代码并提供了创建全局唯一类型的方法。命名空间是避免命名冲突的一种方式。(MSDN)

    3.什么是程序集(Assembly)?它有什么特性。   答:程序集(Assembly)是自我描述的安装单元,由一个或多个文件组成,一个程序集可以是一个包括元数据的DLL或EXE,也可以由多个文件组成。(C#高级编程)   程序集是可重用、无版本冲突并且可自我描述的公共语言运行库应用程序构造块。程序集提供使运行库能够充分了解应用程序的内容并强制使用应用程序定义的版本控制和依赖项规则的结构。这些概念对解决版本控制问题和简化运行库应用程序的部署至关重要。(MSDN)   特性:   (1) 程序集是自我描述的.程序集包含描述程序集的元数据,元数据包括从程序集导出的类和一个清单。   (2) 版本的互相依赖性在程序集的清单中进行了记录。引用程序集的版本被存储在程序集的清单中。   (3) 程序集可以进行并行加载 .在。NET中同一个程序集的不同版本可以在同一个进程中使用。   (4) 应用程序使用应用程序域(Application Domain)来确保其独立性.使用应用域,许多应用程序可以独立的运行在一个进程中。   (5) 安装非简单,只要复制一个程序集中的所有文件。

    4.什么是应用程序域AppDomain?    答1:在.NET结构中,应用程序域是应用程序的一个边界,运行时就不能访问同一个进程中另外一个应用程序的内存,多个应用程序可以运行在多个应用域的一个进程中。(C#高级编程)    答2:应用程序域(通常为 AppDomain)是一个用于隔离应用程序的虚拟进程。在同一应用程序范围内(换句话说,以应用程序入口点开头的对象激活序列中的任何位置)创建的所有对象都创建在同一应用程序域中。多个应用程序域可以存在于单个操作系统进程中,这使它们成为应用程序隔离的轻量方法。    操作系统进程通过提供一个独特的内存地址空间来提供隔离。虽然这很有效,但成本很高,而且不能扩展到大型 Web 服务器所需的数目。另一方面,公共语言运行库通过管理运行在应用程序域中的代码的内存使用来强制应用程序隔离。这可确保它不会访问域边界以外的内存。注意只有类型安全代码才能以这种方式进行管理(运行库在不安全代码加载到应用程序域中时无法保证隔离)很重要。(http://www.w3sky.com/2469.html)     答3:应用程序域 (AppDomain) 可以被看作一个轻型的进程。在一个 Win32 进程中可以存在多个ppDomain。AppDomain 的主要目的是将应用程序和其它应用程序隔离开来。     通过使用独立的地址空间,Win32 进程提供隔离性。这种方法很有效,但开销很大并且伸缩性不好。.NET 运行库通过控制对内存的是用来施加 AppDomain 隔离—AppDomain 中的所有内存是由 .NET 运行库来管理的,所以运行库可以确保 AppDomain 之间不能访问彼此的内存。(http://blog.csdn.net/ianc/)    单个进程可以运行多个应用程序域,并具有在单独进程中所存在的隔离级别。在单个进程中运行多个应用程序提高了服务器伸缩性。

    4. 一列数的规则如下: 1、1、2、3、5、8、13、21、34......  求第30位数是多少, 用递归算法实现。答1:class Recursion  {  static void Main(string[] args)  {            int result;               Recursion rc = new Recursion();   result = rc.RecursionCal(30);   Console.Write("The result:{0}",result);  

      }

      private int RecursionCal(int i)  {   int result;      if( i <= 2)   {    result = 1;   }   else   {    result = RecursionCal(i - 2) + RecursionCal(i - 1);   }   return result;  } }

    答2:

    public class MainClass     {         public static void Main()           {             Console.WriteLine(Foo(30));         }         public static int Foo(int i)         {             if (i <= 0)                 return 0;             else if(i > 0 && i <= 2)                 return 1;             else return Foo(i -1) + Foo(i - 2);         }     }

    5 什么时候使用static?它的优点是什么?使用static应该注意什么?

       当成员函数和成员变量不依赖具体对象,为整个类而非某个对象提供服务时,就使用static。使用static 修饰符声明属于类型本身而不是属于特定对象的静态成员。

    优势:(1)节省内存(2)static的方法就是类级别的,不需实例化出一个对象,即可使用该方法。注意事项:(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。(2)静态数据成员是静态存储的,所以必须对它进行初始化。(C#会自动初始化,C++则需要人工初始化)(3)访问静态成员函数或静态成员变量只能通过类来访问,不能通过对象来访问。

    6 C#中的委托是什么?事件是不是一种委托?

       委托在C#中可以看作是对象的一种新类型。委托把一个方法作为参数传入到另一个方法,通过传递地址的机制完成。它相当于C/C++的函数指针。   事件是一种特殊的委托。委托支持事件处理,可以将事件处理过程注册给委托。触发事件就调用委托。

    7 重载(Overload)、覆盖(Override)、隐藏(Hide)几个的区别

        重载(overload):在一个类中定义方法的不同版本,重载方法的名称相同但是重载的签名不同--即参数名称、参数个数或参数类型不同。只有返回类型相同是不行的。

       覆盖(Override):将基类的方法声明为virtual,在派生类中提供另外一个带有相同签名的方法并在声明中含有override关键字,则重写了基类的方法。

       隐藏(Hide):在基类中方法没有声明为virtual,则在派生类中提供另外一个带有相同签名的方法并在声明中含有new关键字,则新方法隐藏基类的方法。   方法的签名:描述如何调用该方法所需要的一组信息:方法的名称、返回类型,参数个数,参数类型。

    8 请编程实现一个冒泡排序算法?

    答1:C语言

    #include<stdio.h>main(){ int num[10]; int i, j, temp; printf("Please input 10 numbers:/n"); for(i = 0 ; i < 10; i++)  scanf("%d", &num[i]); for(i = 1; i < 10; i++)  for(j = 0; j < 10 - i; j++)  {   if(num[j] > num[j+1])   {             temp = num[j] ;    num[j] = num[j+1];    num[j+1] = temp;   }  } printf("The sorted numbers:/n"); for(i = 0 ; i < 10; i++)  printf("%d/n",num[i]);}

    答2:C#语言

    static void Main(string[] args)  {      int[] num = new int[10];   Console.WriteLine("Please input 10 numbers:");   for(int i = 0; i < 10; i++)    num[i] = Int32.Parse(Console.ReadLine());   for(int i = 1; i < 10; i++)    for(int j = 0; j < 10 - i; j++)    {     if(num[j] > num[j+1])     {                        num[j] = num[j] + num[j+1];      num[j+1] = num[j] - num[j+1];      num[j] = num[j] - num[j+1];     }    }   Console.WriteLine("The sorted numbers:");   for(int i = 0; i < 10; i++)    Console.WriteLine("{0}", num[i]);            }

     

    9 请编程实现一个选择排序算法?

    答1:C语言

    #include<stdio.h>main(){ int num[10]; int i, j, temp; printf("Please input 10 numbers:/n"); for(i = 0 ; i < 10; i++)  scanf("%d", &num[i]); for(i = 0; i < 9; i++)  for(j = i+1; j < 10; j++)  {   if(num[j] < num[i])   {             temp = num[i] ;    num[i] = num[j];    num[j] = temp;   }  } printf("The sorted numbers:/n"); for(i = 0 ; i < 10; i++)  printf("%d/n",num[i]);}

    答2:C#语言

    static void Main(string[] args)  {      int[] num = new int[10];   Console.WriteLine("Please input 10 numbers:");   for(int i = 0; i < 10; i++)    num[i] = Int32.Parse(Console.ReadLine());   for(int i = 0; i < 9; i++)    for(int j = i + 1; j < 10; j++)    {     if(num[j] < num[i])     {      num[i] = num[i] + num[j];      num[j] = num[i] - num[j];      num[i] = num[i] - num[j];     }    }   Console.WriteLine("The sorted numbers:");   for(int i = 0; i < 10; i++)    Console.WriteLine("{0}", num[i]);            }

    10 描述一下C#中索引符的实现过程,是否只能根据数字进行索引?答:C#通过提供索引器,可以象处理数组一样处理对象。定义索引符的方式与定义属性的方式一样,使用get和set函数,索引符的名称是关键字this.实现过程:(1)在类里面定义索引符public string this [int index]   {    get {    if(index < 0 || index > length)    {     throw new IndexOutOfRangeException();    }         return "Value" + index; }

       set{    if(index < 0 || index > length)    {     throw new IndexOutOfRangeException();    }    myObjectValue = value;       }  } (2)使用类创建对象后,就可以使用索引符NewClass newClass = new NewClass();然后就象使用数组一样使用newClass[i]。

    11 索引和属性的异同?相同点:(1)获取对象或是类的静态成员的值。(2)定义类似,使用get和set函数。不同点:(1)类的每一个属性都必须拥有唯一的名称,而类里定义的每一个索引器都必须拥有唯一的签名(signature)或者参数列表(这样就可以实现索引器重载)。 (2)属性可以是static(静态的)而索引器则必须是实例成员。(3)为索引器定义的访问,函数可以访问传递给索引器的参数,而属性访问函数则没有参数。

    12 求以下表达式的值,写出您想到的一种或几种实现方法: 1-2+3-4+……+m答:我写出了三种:答1:private static int CalResult(int m)  {   if(m % 2 == 0)   {    return -(m / 2);   }   else   {    return m - (int)(m / 2);   }  }

    答2:  

    private static int CalResult(int m)  {   int result = 0;   for(int i = 1; i < m + 1; i++)   {    if(i % 2 == 0)    {     result =  result - i;    }    else    {                    result =  result + i;    }   }   return result;  }

    答3:

      private static int CalResult(int m)  {   int result = 0;   for(int i = 1; i < m + 1; i++)   {    result = (i % 2 == 0) ? result - i : result + i;  

         }   return result;  }

    13 CTS、CLS、CLR分别作何解释?

    答1:CTS:公共类型系统。为了实现语言的互操作性,必须有一组各种语言都认可的基本数据类型,这样才能对所有语言进行标准化处理。CTS就提供了这个功能,还提供了定义定制类的规则。CLS:公共语言规范。这是确保代码可以在任何语言中访问的最小标准集体。所有用.NET的编译器都应支持CLS。CLS构成了可以在.NET和IL中使用的功能子集,代码也可以使用CLS外部的功能。如果非CLS功能在代码所在装配件的外部是可见的,那么这些功能就不能在某些语言中使用。CLR:公共语言运行库。它可以处理加载程序、运行程序的代码,以及提供所有支持服务的代码。

    14 什么是受管制的代码和未受管制的代码?

    答:受管制的代码:在.NET环境中运行的任何代码成为受管制的代码(managed code),.NET环境外部的其他代码也运行在Windows上,这些代码称为未受管制的代码(unmanaged code)。

    15 解释一下中间语言(IL)。答:在.NET运行时加载和运行代码时候,这种语言确定代码的位置,在编译受管制的代码时,编译器实际上使用中间语言,CLR处理执行前的最后编译阶段,IL可以非常快速的编译为内部的机器代码,同时支持.NET功能。

    16 解释以下JIT编译。答:Just-in-Time(JIT)编译,表示执行编译过程的最后阶段,即从中间语言转换为内部机器代码。部分代码是按需要即时编译的。

    17 在下面的例子里 class A {  public A()  {   PrintFields();  }  public virtual void PrintFields(){} } class B:A {  int x=1;  int y;  public B()  {   y=-1;  }  public override void PrintFields()  {   Console.WriteLine("x={0},y={1}",x,y);  } }当使用new B()创建B的实例时,产生什么输出?答:答:x=1,y=0

    18 什么是装箱和拆箱?答:装箱是从值类型转换到引用类型。拆箱是从引用类型转换到值类型。

    19 什么是强类型系统?答:每个变量有类型,每个表达式有类型,而且每种类型是严格定义的。其次,所有的数值传递,不管是直接的还是通过方法调用经由参数传过去的都要先进行类型相容性的检查。编译器对所有的表达式和参数都要进行类型相容性的检查以保证类型是兼容的。任何类型的不匹配都是错误的,在编译器完成编译以前,错误必须被改正。

    20 .NET中读写数据库需要用到那些类?他们的作用?答:数据库共享的类:

    DataSet--它创建的对象包含一组DataTables,以及这些表之间的关系。DataTable--它创建的对象作为数据的一个容器,DataTable由一个或多个DataColumn组成,每个DataColumn

    由一个或多个DataRow生成。DataRow-- 类似与数据库表的一行。DataColumn-- 包含列的含义。例如名称和数据类型。Constraint--为DataColumn(或一组数据列)定义规则,例如惟一值。DataColumnMapping--用DataTable中的列名映射数据中的列名。DataTableMapping--将数据库中的表名映射到DataSet中的DataTable中。

    数据库特定的类:

    Sqlcommand、Oledbcommand --SQL语句的包装或存储过程的调用。SqlcommandBuilder、OledbcommandBuilder --用于从一个select子句中生成SQL语句(例如插入、更新、删 除)的类。Sqlconnection、 Oledbconnection--数据库连接SqlDataAdapter、OledbDataAdapter--用语存储选择插入、更新、删除语句的类,因此可以用于生产

    DataSet和更新Database.SqlDataReader、OledbDataReader--只向前的连接数据读取器。DataSet和更新Database.SqlParameter、OledbParameter--为存储过程定义一个参数。SqlTransaction、OledbTransaction--一个数据库处理事物,包装在一个对象中。

     

    21 列举在.NET数据访问中使用的类和接口的命名空间。

    System.Data。包含独立于提供程序的类型,如 DataSet 和 DataTableSystem.Data.SqlClient。包含 SQL Server .NET 数据提供程序类型。 System.Data.OracleClient。包含 Oracle .NET 数据提供程序。 System.Data.OleDb。包含 OLE DB .NET 数据提供程序类型。 System.Data.Odbc。包含 ODBC .NET 数据提供程序类型。

    22 列举 ADO.NET 对象。

    (1)连接的对象Connection对象:表示与数据源之间的连接。可通过Connection对象的各种不同属性指定数据源的类型、位置以及其他属性,可用它来与数据库建立连接或断开连接。Connection对象起到渠道的作用,其他对象如DataAdapter和Command对象通过它与数据库通信。

    Command对象:表示对数据库的查询、对存储过程的调用或要返回特定表内容的直接请求。可使用Command对象对数据库执行任何一种查询操作。

    DataReader对象:DataReder用于以最快的数据检索并检查查询所返回的行。可使用DataReader对象来检查查询结果,一次查询一行,当移到下一行时,前一行的内容就会被放弃。DataReader不支持更新操作,由DataReader返回的数据是只读的。由于DataReader对象支持最小特性集,所以它的速度非常快,而且是轻量的。

    Transaction对象:Connection对象有一个BeginTransaction方法,可用来创建Transaction对象。该对象可用来在 Transaction对象的生存期提交或取消对数据库所做的更改。

    Parameter对象:要使用参数化的Command对象,可先为查询中的每个参数创建Parameter对象,并将它们添加到Command对象的Paramters集合中。ADO.NET的Parameter对象公开一些属性和方法,可用来定义参数的数据类型和值。

    DataAdapter对象:DataAdapter对象充当数据库和ADO.NET对象模型中断开连接的对象之间的桥梁。

    DataAdapter对象会填充DataSet对象中的表,而且能读取缓存的更改并将其提交给数据库。

    (2) 断开连接的对象

    DataTable对象:DataTable对象允许您通过行和列的集合查看数据。通过DataAdapter对象的Fill方法,可以将查询的结果存储在DataTable中。一旦从数据库中读出了数据,将其存储在DataTable对象中,数据与服务器之间的连接就断开拉。DataTable类包含了其他断开连接对象的集合。例如:

    DataRow,DataColumn,Constraints等。

    DataColumn对象:每个DataTable都有一个Columns集合,该集合是DataColumn对象的容器。DataColumn对存储了有关列结构的信息。

    Constraint对象:Constraint对象存在于DataTable对象的Constraints集合中,可以建立一个Constraint对象,确保某一列或多个列中的值在DataTable中是惟一的。

     DataRow对象:想要访问存储在DataTable对象中的实际值,可以使用对象的Rows集合,该集合中包含了一组DataRow对象。DataTable通过DataRows的集合使得所有数据行都可以访问。DataRow对象也是更新的起点。

    DataSet对象:  可以将DataSet对象视为一些DataTable对象的容器。DataSet对象还有一些属性,可以向文件、内存地址写入,或读出该对象;可以只保存DataSet对象的内容或只保存DataSet对象的结构,也可以两者都保存。

    DataRelation对象:DataSet类定义了一个Realtion属性,该属性是DataRelation对象的一个集合,可以使用DataRelation对象来表明DataSet中不同的DataTable对象之间的关系。DataRelation对象还引入了一些属性,来强化引用的完整性。

    DataView对象:一旦获取了DataTable对象中查询的结果,就可以使用DataView对象以不同方式来查看数据。可以使用多个DataView对象在同时查看同一DataTable。

    (http://www.sozz.cn/00091/27353.htm

    23 在C#中,string str = null 与 string str = “” 请尽量使用文字或图象说明其中的区别。 答:string str = null 是不给他分配内存空间,而string str = "" 给它分配长度为空字符串的内存空间。

    24 请详述在dotnet中类(class)与结构(struct)的异同?答1:类是一种数据结构,它可以包含数据成员(常数和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数、析构函数),以及嵌套类型。类类型支持继承,它使派生类可以对基类进行扩展和专用化。    结构也可以包含数据成员和函数成员,对于具有值语义的小的数据结构很有用。    类(class)可以被实例化,属于引用类型,是分配在内存的堆上的。类类型的变量包含对数据的引用。    结构(struct)属于值类型,是分配在内存的栈上的. 结构类型的变量直接包含结构的数据。当它们只有少量数据成员,不要求使用继承或引用标识,而且它们适合使用值语义,这时候使用结构。    与类不同,结构不支持继承。结构类型永远不是抽象的,并且始终是隐式密封的。    结构不能声明无参数的实例构造函数。实际上每个结构类型都隐含地含有一个无参数实例构造函数,将所有的值类型设置为它们的默认值,并将所有引用类型字段设置为null.    结构不能声明析构函数。    结构的实例字段不能设置初始值,但是静态字段声明中可以设置初始值。    this意义不同。在类的实例构造函数和实例函数成员中,this为值类别.this可以用语引用该函数成员调用所涉及的实例,但是不可能在类的函数成员中对this本身赋值。     在结构的实例构造函数中,this为变量类别,相当于该结构类型的out参数,而在结构的实例函数成员内,this相当于该结构类型的ref参数。

    答2:结构与类共享几乎所有相同的语法,但结构比类受到的限制更多:尽管结构的静态字段可以初始化,结构实例字段声明还是不能使用初始值设定项。结构不能声明默认构造函数(没有参数的构造函数)或析构函数。结构的副本由编译器自动创建和销毁,因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值(参见默认值表)来实现默认构造函数。结构不能从类或其他结构继承。结构是值类型 -- 如果从结构创建一个对象并将该对象赋给某个变量,变量则包含结构的全部值。复制包含结构的变量时,将复制所有数据,对新副本所做的任何修改都不会改变旧副本的数据。由于结构不使用引用,因此结构没有标识 -- 具有相同数据的两个值类型实例是无法区分的。C# 中的所有值类型本质上都继承自 ValueType,后者继承自 Object。编译器可以在一个称为装箱的过程中将值类型转换为引用类型。

    25 params,ref,out 三者。

         params 关键字可以指定在参数数目可变处采用参数的方法参数。在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。     方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。属性不是变量,不能作为 out 参数传递。如果两个方法的声明仅在 out 的使用方面不同,则会发生重载。     方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。 若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。传递到 ref 参数的参数必须最先初始化。属性不是变量,不能作为 ref 参数传递。如果两种方法的声明仅在它们对 ref 的使用方面不同,则将出现重载。

    26 分析以下代码,完成填空 string strTmp = "abcdefg某某某"; int i= System.Text.Encoding.Default.GetBytes(strTmp).Length; int j= strTmp.Length; 以上代码执行完后,i= j= 答:i=13,j=10

    27 根据线程安全的相关知识,分析以下代码,当调用test方法时i>10时是否会引起死锁?并简要说明理由。public void test(int i) {    lock(this)  {    if (i>10)    {      i--;      test(i);    }  } }答:不会发生死锁,(但有一点int是按值传递的,所以每次改变的都只是一个副本,因此不会出现死锁。但如果把int换做一个object,那么死锁会发生)

    28 面向对象的语言具有________性、_________性、________性答:封装、继承、多态。

    29 能用foreach遍历访问的对象需要实现 ________________接口或声明________________方法的类型。答:IEnumerable 、 GetEnumerator。

    30 GC是什么? 为什么要有GC?答:GC是垃圾收集器。程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以

    调用下面的方法之一:   System.gc()  Runtime.getRuntime().gc()

    31 String s = new String("xyz");创建了几个String Object?答:两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。

    32 abstract class和interface有什么区别?  答:声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。  接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。(1)一个类可以实现任意多个接口,但是最多只能对一个抽象类进行子类化。(2)一个抽象类可以包括非抽象方法,而一个接口所有的方法都是抽象的(3)一个可以使用变量,而一个接口不能(4)一个抽象类的方法可以有各种访问修饰符,但是在声明接口时候不允许有访问修饰符,默认为public.(5)一个抽象类可以定义构造函数,而一个接口不能。(C#设计模式)补充:一个C#接口可以包含方法,属性,事件和索引器,但是不能包容委托?delegate关键字引入的是一个新的类型,而event关键字引入的是一个新的成员。一个接口声明规范了成员,而不是类型。所以不能包含委托。

    33 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类是可继承实体类,但前提是实体类必须有明确的构造函数。

    34 类继承和接口继承答:类继承不仅说明继承,而且也实现继承;接口继承只说明继承。换句话说,派生类可以继承基类的方法实现,而派生的接口只继承了父接口的成员方法说明,而没有继承父接口的实现。  类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口。

    35 启动一个线程是用run()还是start()?答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。  36 构造器Constructor是否可被override?答:构造器Constructor不能被继承,因此不能覆盖Override,但可以被重载Overloading。

    37 是否可以继承string类?  string类型是直接从object继承的密封类类型,不能被继承。

    38 try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?答:会执行,在return前执行。  39 swtich是否能作用在byte上,是否能作用在long上,是否能作用在string上?  答:switch(expr1)中,expr1是一个表达式,类型为sbyte,byte,short,ushort,int ,uint,long,ulong,char,string或枚举类型。所以能作用在byte,long和string上。

    40 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?  答:不能,一个对象的一个synchronized方法只能由一个线程访问。

    41 使用抽象方法和抽象类有什么优点?答:一 可以使用类具有更好的层次结构,该结构能更清晰地反映我们建立的模型;二是使用抽象类可以把某些很难定位的运行时错误变成易于定位的编译时错误。

    42 抽象方法(abstract的method)的特性?是否可同时是static,是否可同时是native,是否可同时是synchronized?答:抽象方法具有以下特性:抽象方法是隐式的虚方法,只允许在抽象类中使用抽象方法声明,抽象方法声明不提供实际的实现。在抽象方法声明中使用 static 或 virtual 修饰符是错误的。都不能。(Native 序列化格式使用非常简单的算法,使 SQL Server 能够在磁盘上存储 UDT 的有效表示形式。标记为 Native 序列化的类型只能将值类型(在 Microsoft Visual C# 中为 struct,在 Microsoft Visual Basic .NET 中为 structure)用作成员。不支持引用类型(如 Visual C# 和 Visual Basic 中的类)的成员,无论它们是用户定义的成员还是框架中已有的成员(如 String),均是如此。 (来自MSDN))

    43 进程和线程的区别?答:进程是系统进行资源分配和调度的单位;线程是CPU调度和分派的单位,一个进程可以有多个线程,这些线程共享这个进程的资源。

    44 堆和栈的区别?答:    栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。    堆:一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上。

    45 成员变量和成员函数前加static的作用?答:它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数。分别用来反映类的状态。

    46 请指出GAC的含义?答:全局程序集缓存。

    47 在c#中using和new这两个关键字有什么意义,请写出你所知道的意义?答: using 关键字:using 指令:   创建命名空间的别名, 导入在其他命名空间中定义的类型using 语句:   定义一个范围,在此范围末尾将处置对象。 在 using 语句中创建一个实例,确保退出using 语句时在对象上调用 Dispose(执行与释放或重置非托管资源相关的应用程序定义的任务。).实例化的对象必须实现 System.IDisposable 接口。

    new 关键字:new 运算符:  用于在堆上创建对象和调用构造函数。 new 修饰符:  用于隐藏基类成员的继承成员。new 约束:    用于在泛型声明中约束可能用作类型参数的参数的类型。

    48 需要实现对一个字符串的处理,首先将该字符串首尾的空格去掉,如果字符串中间还有连续空格的话,仅保留一个空格,即允许字符串中间有多个空格,但连续的空格数不可超过一个.答:string inputStr=" xx   xx  ";inputStr=Regex.Replace(inputStr.Trim()," *"," ");

    49 C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?答:一个是属性,用于存取类的字段,一个是特性,用来标识类,方法等的附加性质

    50  #inline,#region,#endregion, #warning, #error.答: #region,#endregion 指令用于把一段代码标记为有给定名称的一个块。#inline 指令用于改变编译器在警告和错误信息中显示文件名和行号信息。#warning 编译器遇见它会产生一个警告。#error 编译器遇见它会产生一个错误。


    最新回复(0)