C#学习笔记(三)—–C#高级特性中的委托与事件(上)

C#高级特性中的委托与事件(上)


委托

  • 委托是一种知道如何调用方法的对象。委托类型定义了委托对象可以调用的方法。具体的,它定义了方法的签名。包括方法的返回类型和方法的参数类型和数量。
  • 委托的实例实际上是调用者的代表,调用者先调用委托,委托再调用方法。这种间接的方式可以将调用这和委托分开。提示:技术上,我们把没有括号和参数的方法叫做方法组,如果一个方法被重载,那我们可以根据方法的参数类型和数量来决定使用哪一个方法。
  • 从C#2.0开始,把一个方法组赋值给一个委托的变量可以创建一个委托实例:
public delegate DoSomething();
public void Do()
{
Console.WriteLine(.......)
}
DoSomething=Do;
  • 委托实际是特殊的类。虽然C#标准没有确切规定类的层次结构应该是怎样的,但委托必须直接或间接地派生自System.Delegate。事实上,.NET中的委托类型总是派生自System.MulticastDelegate,后者又从System.Delegate派生:

委托
第一个属性属于(System.Reflection.MethodInfo)类型,MethodInfo描述了特定方法的签名,包括方法名称、参数和返回类型。除了MethodInfo,委托还需要一个对象实例,其中包含了要调用的方法。这正是第二个属性Target的作用。在静态方法的情况下,Target对应于类型自身。

  • 实例方法和静态方法的Target属性:当委托对象指向一个实例方法时,委托对象不仅要维护这个方法的引用,而且还会维护到这个实例方法所属类的引用。System.Delegate的Target属性可以表示这个实例方法所属的类。

  • 用委托写插入式的方法:一个委托变量会在运行时被指定一个方法。这个特性对于编写插件式的方法特别有用,本例中有一个名为Transform的公共方法,他对整型数组的每个元素进行变换,为了指定变换的方式,定义了一个名为TransFormer的委托参数:

public delegate int Transformer (int x);//定义的委托会在运行时与Util类中的Transform进行绑定
class Util
{
public static void Transform (int[] values, Transformer t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t (values[i]);
}
}
class Test
{
static void Main()
{
int[] values = { 1, 2, 3 };
Util.Transform (values, Square); // Hook in the Square method
foreach (int i in values)
Console.Write (i + " "); // 1 4 9
}
static int Square (int x) { return x * x; }
}
  • 多播委托:所有的委托实例都有多播的能力,意思是一个委托可以”关联“多个目标方法。委托的+=操作符表示为向委托注册订阅者,通过委托向订阅者发布消息(委托为事件发布者)。用+和+=联合多个委托实例,例如:
SomeDelegate d = SomeMethod1;
d += SomeMethod2;

现在d不仅可以调用Some Method1,还可以调用SomeMethod2。委托按照添加的顺序依次被触发。运算符-和-=可以从左边的委托操作数中一出右边的委托操作数。

d-=SomeMethod1;

现在d只能触发SomeMethod2。
在值为null的delegate上面执行+=相当于为委托赋新值。

SomeDelegate d = null;
d += SomeMethod1;//当SomeDelegate为null时等价于d = SomeMethod1;

同样的,为只有一个目标方法的委托上面使用-或者-=相当于给委托赋予一个null值:

  • 提示:委托是不可变的,因此调用-=或+=操作符实质上是新创建一个委托实例,并把他赋值给已有变量。
  • 提示:所有的委托类型都派生自System.MulticastDelegate,后者派生自System.Delegate。C#编译器使用+, -,+=, 和 -=构成System.Delegate类的静态Combine和Remove方法。
  • 多播委托的实例
    假如有一个需要运行很长时间的例程,里面的System.Threading.Thread.Sleep (100);用来模拟运行很长时间的程序。
public delegate void ProgressReporter (int percentComplete);
public class Util
{
public static void HardWork (ProgressReporter p)
{
for (int i = 0; i < 10; i++)
{
p (i * 10); // 调用委托
System.Threading.Thread.Sleep (100); // 模拟长时间的运行
}
}
}

为了监视执行进度,在Main方法中建立一个多播委托实例p,分别用两个方法来对程序的进度进行监视。

class Test
{
static void Main()
{
X x = new X();
ProgressReporter p = x.InstanceProgress;
p(99); // 99
Console.WriteLine (p.Target == x); // True
Console.WriteLine (p.Method); // Void InstanceProgress(Int32)
}
}
class X
{
public void InstanceProgress (int percentComplete)
{
Console.WriteLine (percentComplete);
}
}
  • 委托中的泛型:委托可以引入类型参数:public delegate T Transformer<T> (T arg);
  • 根据上面的定义,可以定义一个泛化的方法来对任何类型都生效:
public class Util
{
public static void Transform<T> (T[] values, Transformer<T> t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t (values[i]);
}
}
class Test
{
static void Main()
{
int[] values = { 1, 2, 3 };
Util.Transform (values, Square); // Hook in Square
foreach (int i in values)
Console.Write (i + " "); // 1 4 9
}
static int Square (int x) { return x * x; }
}
  • Func和Action委托:Func和Action可以代表绝大多数的方法,它们定义在System中:
delegate TResult Func <out TResult> ();
delegate TResult Func <in T, out TResult> (T arg);
delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2);
... and so on, up to T16
delegate void Action ();
delegate void Action <in T> (T arg);
delegate void Action <in T1, in T2> (T1 arg1, T2 arg2);
... and so on, up to T16

这些委托现在使用的非常普遍,前面举例的Transformer委托,可以用一个Func

public static void Transform<T> (T[] values, Func<T,T> transformer)
{
for (int i = 0; i < values.Length; i++)
values[i] = transformer (values[i]);
}

只有ref/out和指针没有在这些委托中涉及到。
在.net framework2.0之前,大多数代码使用的还是自定义的委托类型,因为那个时候还没有泛型,也不存在Func和Action。
- 委托和接口:能用委托解决的问题,都能用接口解决。例如:

public interface ITransformer
{
int Transform (int x);
}
public class Util
{
public static void TransformAll (int[] values, ITransformer t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t.Transform (values[i]);
}
class Squarer : ITransformer
{
public int Transform (int x) { return x * x; }
}
...
static void Main()
{
int[] values = { 1, 2, 3 };
Util.TransformAll (values, new Squarer());
foreach (int i in values)
Console.WriteLine (i);
}
  • 在下面的情形中,如果有一条或者多条符合情况,委托可能是比接口更好的选择:
    ①接口内只定义一个方法
    ②需要多播能力
    ③订阅者需要多次实现接口
    订阅者为了实现不同的计算,可能会提供多个类来实现接口(比如平方或者立方转换),如果使用接口,类只能实现一次接口,所以必须写多个类来重写接口方法来实现不同的功能,这样看起来很傻:
class Squarer : ITransformer
{
public int Transform (int x) { return x * x; }
}
class Cuber : ITransformer
{
public int Transform (int x) {return x * x * x; }
}
...
  • 委托的兼容性:即使签名相同,委托也互不兼容:
delegate void D1();
delegate void D2();
...
D1 d1 = Method1;
D2 d2 = d1; // Compile-time error

提示:但是允许下面的写法:

D2 d2 = new D2 (d1);
  • 如果委托实例指向相同的方法,则认为它们是等价的。
  • 如果多播委托按照相同的顺序指向相同的方法,则认为它们是等价的。

委托的逆变和协变

  • 参数的兼容性:当调用一个方法时,可以给参数提供一个大于该参数的类型的参数,这是正常的多态行为:
 class Animal{}   
 class Bird : Animal{}  
 class Sparrow : Bird{}
 static void Do(Bird shit){}
 static void Main(string[] args)
        {
            Animal animal=new Animal();
            Sparrow sparrow=new Sparrow();
            Do(animal);//错误,无法从Animal转换为Bird:Bird=Animal这个向下转换是不安全的
            Do(sparrow);//正确:Bird=Sparrow,向上转换是安全的
        }      
  • 基于同样的原理,可以给委托的类型参数提供大于该类型参数的类型的类型参数,这个叫做委托的逆变(这个问题的讨论将在后续继续展开)。
delegate void StringAction (string s);
class Test
{
static void Main()
{
StringAction sa = new StringAction (ActOnObject);
sa ("hello");
}
static void ActOnObject (object o)
{
Console.WriteLine (o); // hello
}
}

委托只是代替其他类来调用方法。在本例中,当调用StringAction时,使用的是string类型的参数,当这个string类型的参数被转发到目标方法时(在本例中一个object类型参数的方法),string将被向上转换为object(隐式)。

  • 返回类型的兼容性:如果调用一个方法,返回值的类型可能是比你请求的类型的一个更细化的(more specific)类型(子类),也就是说返回了一个更特殊的类型,(一般情况下我们说子类比基类更特殊,更细化)这也是正常的多态行为:
 class Animal{}
 class Bird : Animal{}
 class Sparrow : Bird{}
 static Bird Do()
        {
            return  new Bird();
        }   
  Animal animal=new Animal();
            Sparrow sparrow=new Sparrow();
            animal = Do();
            sparrow = Do(); //转换失败,Bird无法隐式转换成Sparrow        

在这里可以总结下:在输入位置提供一个子类或者在输出位置提供一个基类,都是安全的,都是多态的表现,反之则不然。

  • 基于同样的道理,委托可以返回一个比它自身描述的返回类型更详细的类型,这个称为委托的协变。
delegate object ObjectRetriever();
class Test
{
static void Main()
{
ObjectRetriever o = new ObjectRetriever (RetriveString);
object result = o();
Console.WriteLine (result); // hello
}
static string RetriveString() { return "hello"; }
}

ObjectRetriever期望返回一个object,而它指向的方法返回一个string。

  • 泛型委托类型参数的可变性(协变和逆变):泛型的委托和泛型的接口一样,都支持类型参数的协变和逆变。如果定义了一个泛型的委托,最好按照如下的准则进行:
    ①将只用在返回(输出)位置的类型参数标注为协变的(out)
    ②将只用在参数(输入)位置的类型桉树标注为逆变的(in)
    这样做可以使转换自然的遵循类型的继承关系(其实本质上说都是向上转换是类型安全的,因为不管是协变还是逆变,实现的都是向上转换)。
    下面的委托支持协变:
delegate TResult Func<out TResult>();

允许:

Func<string> x = ...;
Func<object> y = x;

下面的委托支持逆变:

delegate void Action<in T> (T arg);

允许:

Action<object> x = ...;
Action<string> y = x;

事件

  • 在使用委托的环境中一般会出现两种角色:广播这和订阅者。广播者是包含委托字段的类,它决定什么时候去传播消息(意即调用委托)。订阅者是目标方法,通过在广播者的委托上面调用+=和-=操作符,来决定什么时候开始或者结束对广播这的监听(注册或取消注册),一个订阅者不知道也不干涉其他订阅者。
  • 事件是使这一模式正式化的语言形态。事件是只显示委托中广播/订阅需要的子特性的结构。使用事件的主要目的在于:保护订阅者之间的互不干涉。
  • 声明事件最好的方法就是在委托类型前面添加event关键字:
// Delegate definition
public delegate void PriceChangedHandler (decimal oldPrice,decimal newPrice);
public class Broadcaster
{
// Event declaration
public event PriceChangedHandler PriceChanged;
}

Broadcaster类中的代码对PriceChanged有完全的访问权限,并把它当作一个委托,Broadcaster类外的代码只能使用+=和-=在PriceChanged事件上。

  • (这个是我在C#本质论里面的记录)在使用委托时,一个非常容易犯的错误就是在本该使用+=操作符的时候使用了=操作符,结果就是将一个委托变量错误的指向了另一个委托实例。由于这是一个非常容易犯的错误,最好的解决方法就是
    仅为包容类内部的对象提供对赋值操作符的支持。event关键字的作用就是提供额外的封装,避免不小心地取消其他订阅者。
    委托和事件的第二个区别就是,事件确保只有包容类才能触发事件的通知。
    在类中定义事件非常容易,就是在定义委托字段的基础上添加event关键字,event关键字提供了对委托需要的一切封装。这里简单总结一下事件的编码规范:第一个参数sender是object类型的,它包含对调用委托的那个对象的一个引用(静态事件则为null)。第二个参数是System.EventArgs类型的
    (或者从System.EventArgs派生,但包含了事件的附加数据)。调用委托的方式和以前几乎完全一样,只是要提供附加的参数。
【面试题库网整理 .net 面试题(附答案)(四)】 7. 某一密码仅使用K、L、M、N、O共5个字母,密码的单词从左向右排列,密码单词必须遵循如下规则: (1) 密码单词的最小长度是两个字母,可以相同,也可以不同 (2) K不可能是单词的第一个字母 (3) 如果L出现,则出现次数不止一次 (4) M不能使最后一个也不能是倒数第二个字母 (5) K出现,则N就一定出现 (6) O如果是最后一个字母,则L一定出现 问题一:下列哪一个字母可以放在LO的O后面,形成一个3个字母的密码单词? A) K B)L C) M D) N 答案:B 问题二:如果能得到的字母是K、L、M,那么能够形成的两个字母长的密码单词的总数是多少? A)1个 B)3个 C)6个 D)9个 答案:A 问题:下列哪一个是单词密码? A) KLLN B) LOML C) MLLO D)NMKO 答案:C 8. 62-63=1 等式不成立,请移动一个数字(不可以移动减号和等于号),使得等式成立,如何移动? 答案:62移动成2的6次方 new有几种用法 第一种:new Class(); 第二种:覆盖方法 public new XXXX(){} 第种:new 约束指定泛型类声明的任何类型参数都必须有公共的无参数构造函数。 2.如何把一个array复制到arrayList里 foreach( object o in array )arrayList.Add(o); 3.datagrid.datasouse可以连接什么数据源 [dataset,datatable,dataview] dataset,datatable,dataview , IList 4.概述反射和序列化 反射:程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型。然后,可以调用类型的方法或访问其字段和属性 序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。 5.概述o/r mapping 的原理 利用反射,配置 将类于数据库表映射 7.用sealed修饰的类有什么特点 sealed 修饰符用于防止从所修饰的类派生出其它类。如果一个密封类被指定为其它类的基类,则会发生编译时错误。 密封类不能同时为抽象类。 sealed 修饰符主要用于防止非有意的派生,但是它还能促使某些运行时优化。具体说来,由于密封类永远不会有任何派生类,所以对密封类的实例的虚拟函数成员的调用可以转换为非虚拟调用来处理。 11.详述.NET里class和struct的异同! class:放在 ? struct放在? struct值传递 类与结构有很多相似之处:结构可以实现接口,并且可以具有与类相同的成员类型。然而,结构在几个重要方面不同于类:结构为值类型而不是引用类型,并且结构不支持继承。结构的值存储在“在堆栈上”或“内联”。细心的程序员有时可以通过聪明地使用结构来增强性能。 12.概述.NET里对 remoting 和 webservice 两项技术的理解和实际的应用。 远程逻辑调用,remoing接口只能用在.net 13.什么是code-behind技术 aspx and cs 14.概述层结构体系 web/business/dataaccess 15.asp.net如何实现MVC模式,举例说明! web/business/dataaccess 2.什么是ASP.net的用户控件 答:用户控件就是.ascx扩展名的东西喽,可以拖到不同的页面调用,以节省代码.比如登陆可能在多个页面上有,就可以做成用户控件,但是有一个问题就是用户控件拖到不同级别的目录下后里面的图片等的相对路径会变得不准确,需要自已写方法调整. 3.什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释? 答:装箱就是把值类型转成引用类型,从MS IL角度看好像是boxing,没记错的话是把值从堆栈转到堆.拆箱相反,重载就是指一个方法名同,参数个数不同,返回值可以相同的方法.CLR是通用语言运行时,其它的不清楚. 4.列举一下你所了解的XML技术及其应用 答:XML可是好东西,保存配置,站与站之间的交流,WEB SERVICE都要用它. 5.值类型和引用类型的区别?写出C#的样例代码。 答:结构是值类型,类是引用类型,所以传结构就是值类型的应用啦,传对象或类就是引用类型的,这个不用多写了吧. 6.ADO.net常用的对象有哪些?分别描述一下。 答:connection command sqladapter dataset datatable dataview等等.写不完了. 7.如何理解委托? 答:据说相当于函数指针,定义了委托就可以在不调用原方法名称的情况下调用那个方法. msdn2005是这样解释的: 委托具有以下特点: 委托类似于 C++ 函数指针,但它是类型安全的。 委托允许将方法作为参数进行传递。 委托可用于定义回调方法。 委托可以链接在一起;例如,可以对一个事件调用多个方法。 方法不需要与委托签名精确匹配。有关更多信息,请参见协变和逆变。 C# 2.0 版引入了匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。 【面试题库网整理 .net 面试题(附答案)()】 22.您要创建一个显示公司员工列表的应用程序。您使用一个DataGrid控件显示员工的列表。您打算修改这个控件以便在这个Grid的Footer显示员工合计数。请问您应该怎么做?( C? ) A.重写OnPreRender事件,当Grid的Footer行被创建时显示合计数。 B.重写OnItemCreated事件,当Grid的Footer行被创建时显示合计数。 C.重写OnItemDataBound事件,当Grid的Footer行被创建时显示合计数。 D. 重写OnLayout事件,当Grid的Footer行被创建时显示合计数。 23.您要创建ASP.NET应用程序用于运行AllWin公司内部的Web站点,这个应用程序包含了50个页面。您想要配置这个应用程序以便当发生一个HTTP代码错误时它可以显示一个自定义的错误页面给用户。您想要花最小的代价完成这些目标,您应该怎么做?(多选)( CD )   A.在这个应用程序的Global.asax文件创建一个Application_Error过程去处理ASP.NET代码错误。   B.在这个应用程序的Web.config文件创建一个applicationError节去处理ASP.NET代码错误。   C.在这个应用程序的Global.asax文件创建一个CustomErrors事件去处理HTTP错误。   D.在这个应用程序的Web.config文件创建一个CustomErrors节去处理HTTP错误。   E.在这个应用程序的每一页添加一个Page指示符去处理ASP.NET 代码错误。   F. 在这个应用程序的每一页添加一个Page指示符去处理ASP.NET HTTP错误。 24.您的公司有一个DB Server,名为AllWin,其上装了MS SQLSERVER 2000。现在需要您写一个数据库连接字符串,用以连接AllWin上SQL SERVER的一个名为PubBase实例的Test库。请问,应该选择下面哪一个字符串?( B )   A. “Server=AllWin;Data Source=PubBase;Initial Catalog=Test;Integrated Security=SSPI”   B. “Server= AllWin;Data Source=PubBase;Database=Test;Integrated Security= SSPI”   C. “Data Source= AllWin \PubBase;Initial Category=PubBase;Integrated Security= SSPI”   D. “Data Source= AllWin \ PubBase;Database=Test;Integrated Security= SSPI” 25.您为AllWin公司创建了一个ASP.NET应用程序。这个应用程序调用一个 Xml Web Service。这个 Xml Web Service 将返回一个包含了公司雇员列表的DataSet对象。请问您该如何在这个程序使用这个 Xml Web Service?( ? )   A.在“引用”对话框的.Net标签选择 System.Web.Services.dll。   B.在“Web引用”对话框输入这个 XML Web service 的地址。   C.在您的 Global.asax.cs 添加一条 using 语句并指定这个 XML Web service 的地址。   D.在您的 Global.asax.cs 写一个事件处理器导入这个 Xml Web Service 相应的 .wsdl 和 .disco 文件。 26.您要创建一个ASP.NET应用程序在DataGrid控件显示一个经过排序的列表。产品数据被存放于一个名为PubBase的Microsoft SQL Server 数据库。每个产品的主键是ProductID,Numeric型并且每个产品有一个字母描述字段,名为ProductName。您使用一个SqlDataAdapter对象和一个SqlCommand对象通过调用一个存储过程从数据库获取产品数据。您将SqlCommand对象的CommandType属性设置为CommandType.StoredProcedure,并将它的CommandText属性设置为procProductList。您成功的获取了一个DataTable对象,其是已经按ProductID降序排列的产品列表。您打算显示以相反的字母顺序排列的ProductName,请问该怎么做? ( B )   A. 将SqlCommand对象的CommandType属性修改为CommandType.Text,将CommandText属性修改为”SELECT * FROM procProductList ORDER BY ProductName DESC”。然后将这个DataTable对象绑定到DataGrid控件。   B. 创建一个基于这个DataTable对象的新的DataView并将这个DataView的Sort属性设置为“ProductName DESC”。然后将这个DataView对象绑定到DataGrid控件。   C. 将DataGrid控件的AllowSorting属性设置为True,并将DataGridColumn的SortExpression属性设置为 “ProductName DESC”.以显示ProductName。然后将这个DataTable对象绑定到DataGrid控件。   D. 将DataTable对象的DisplayExpression属性设置为 “ORDER BY ProductName DESC”.。然后将这个DataTable对象绑定到DataGrid控件。 76.C#代码实现,确保windows程序只有一个实例(instance) ///<summary> ///应用程序的主入口点。 ///</summary> [STAThread] staticvoid Main() { //防止程序多次运行 if(!OneInstance.IsFirst("GetPayInfo")) { MessageBox.Show ("警告:程序正在运行! 请不要重复打开程序!可在右下角系统栏找到!","程序错误提示:",MessageBoxButtons.OK,MessageBoxIcon.Stop); return; } Application.Run(new Form1()); } // ******************* 防止程序多次执行 ************************** publicabstractclass OneInstance { ///<summary> ///判断程序是否正在运行 ///</summary> ///<param name="appId">程序名称</param> ///<returns>如果程序是第一次运行返回True,否则返回False</returns> publicstaticbool IsFirst(string appId) { bool ret=false; if(OpenMutex(0x1F0001,0,appId)==IntPtr.Zero) { CreateMutex(IntPtr.Zero,0,appId); ret=true; } return ret; } [DllImport("Kernel32.dll",CharSet=CharSet.Auto)] privatestaticextern IntPtr OpenMutex( uint dwDesiredAccess, // access int bInheritHandle, // inheritance option string lpName // object name ); [DllImport("Kernel32.dll",CharSet=CharSet.Auto)] privatestaticextern IntPtr CreateMutex( IntPtr lpMutexAttributes, // SD int bInitialOwner, // initial owner string lpName // object name ); } 【面试题库网整理 .net 面试题(附答案)(二)】 8.以下代码段能否编译通过?请给出理由。 try { } catch(FileNotFoundException e1) { } catch(Exception e2) { } catch(IOException e3) { } catch { } 9.对于一个实现了IDisposable接口的类,以下哪些项可以执行与释放或重置非托管资源相关的应用程序定义的任务?(多选) ( ABC ) A.Close B.DisposeC.Finalize D.using E.Quit 10.Net依赖以下哪项技术实现跨语言互用性?( C ) A.CLR B.CTS C.CLS D.CTT 11.请问: String类与StringBuilder类有什么区别?为什么在.Net类库要同时存在这2个类?(简答) 如果要操作一个不断增长的字符串,尽量不用String类,改用StringBuilder类。两个类的工作原理不同:String类是一种传统的修改字符串的方式,它确实可以完成把一个字符串添加到另一个字符串上的工作没错,但是在.NET框架下,这个操作实在是划不来。因为系统先是把两个字符串写入内存,接着删除原来的String对象,然后创建一个String对象,并读取内存的数据赋给该对象。这一来二去的,耗了不少时间。而使用System.Text命名空间下面的StringBuilder类就不是这样了,它提供的Append方法,能够在已有对象的原地进行字符串的修改,简单而且直接。当然,一般情况下觉察不到这二者效率的差异,但如果你要对某个字符串进行大量的添加操作,那么StringBuilder类所耗费的时间和String类简直不是一个数量级的。 12.以下哪个类是int的基类?( ) A.Int32 B.Object C.ValueType D.Int16 二、C# 部分* 13.以下哪些可以作为接口成员? (多选) ( ABDE ) A.方法B.属性C.字段D.事件E.索引器 F.构造函数G.析构函数 14.以下关于ref和out的描述哪些项是正确的?(多选) ( ACD ) A.使用ref参数,传递到ref参数的参数必须最先初始化。 B.使用out参数,传递到out参数的参数必须最先初始化。 C.使用ref参数,必须将参数作为ref参数显式传递到方法。 D.使用out参数,必须将参数作为out参数显式传递到方法。 15.“访问范围限定于此程序或那些由它所属的类派生的类型”是对以下哪个成员可访问性含义的正确描述?( B ) A.public B.protected C.internal D.protected internal 16.class Class1 { private static int count = 0; static Class1() { count++; } public Class1() { count++; } } Class1 o1 = new Class1(); Class1 o2 = new Class1(); 请问,o1.Count的值是多少?( C ) A.1 B.2 C.3 D.4 17.abstract class BaseClass { public virtual void MethodA() { } public virtual void MethodB() { } } class Class1: BaseClass { public void MethodA(string arg) { } public override void MethodB() { } } class Class2: Class1 { new public void MethodB() { } } class MainClass { public static void Main(string[] args) { Class2 o = new Class2(); Console.WriteLine(o.MethodA()); } } 请问,o.MethodA调用的是: ( A ) A.BaseClass.MethodAB.Class2.MethodA C.Class1.MethodAD.都不是 【.net 面试题系列文章一(附答案)】 1 (1)面向对象的语言具有__继承性_性、_封装性_性、_多态性 性。 (2)能用foreach遍历访问的对象需要实现 _ IEnumerable 接口或声明_ GetEnumerator 方法的类型。1.c#元运算符是__?:__ 2.当整数a赋值给一个object对象时,整数a将会被__装箱___? 3.类成员有__3__种可访问形式? 4.public static const int A=1;这段代码有错误么?是什么? const成员都是static所以应该去掉static 5.float f=-123.567F; int i=(int)f; i的值现在是_-123____? 6.利用operator声明且仅声明了==,有什么错误么? 要同时修改Equale和GetHash() ? 重载了"==" 就必须重载 "!=" 7.委托声明的关键字是___ delegate ___? 8.用sealed修饰的类有什么特点?不可被继承 9.在Asp.net所有的自定义用户控件都必须继承自_ System.Web.UI.UserControl _______? 10.在.Net所有可序列化的类都被标记为__[serializable]___? 11.在.Net托管代码我们不用担心内存漏洞,这是因为有了_ gC __? 12.下面的代码有什么错误吗?_ abstract override 是不可以一起修饰______ using System; class A { public virtual void F(){ Console.WriteLine("A.F"); } } abstract class B:A { public abstract override void F(); } 13.当类T只声明了私有实例构造函数时,则在T的程序文本外部,_不可以_(可以 or 不可以)从T派生出新的类,_不可以_(可以 or 不可以)直接创建T的任何实例。 14.下面这段代码有错误么?case():不行 default; switch (i){ case(): CaseZero(); break; case 1: CaseOne(); break; case 2: dufault; CaseTwo(); break; } 15.在.Net,类System.Web.UI.Page 可以被继承么?可以
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值