反射赋值的有关,NET面试题解析

C#中字段、属性和构造函数赋值的题材

0. 目录

C#6
骤增特色目录

[C#6] 5-自动属性增强,

  体系小说目录地址:

提出难点

第二建议多少个难题:

壹 、如何兑现和谐的注入框架?

贰 、字段和自行属性的界别是什么样?

三 、字段和机动属性注解时的第壹手赋值和构造函数赋值有哪些差别?

④ 、为啥只读字段和只读自动属性(唯有get没有set访问器)都得以在构造函数中开始展览赋值?

五 、反射能够给只读字段或然只读属性举办赋值吗?

六 、自动属性和一般属性的分歧?

那一个标题是本人在试着写本身的注入完成时境遇的难题。那个题材应该在就学C#时的第四节课就活该学到了,小编看网上还有人享受说他在面试时相遇面试官问为啥只读字段和只读自动属性能够在构造函数中展开赋值,他从没应答上来,然后她写著作商讨那么些标题,却从没汲取一个显眼的答案,实在心痛。网上关于只读属性有个别是写ReadOnly本性的,读到那么些小说直接跳过啊,老版本的C#现行反革命看也没怎么援助。

1. 老版本代码

 1 internal class Person
 2 {
 3     public string Name { get; private set; }
 4     public int Age { get; private set; }
 5 
 6     public Person(string name,int age)
 7     {
 8         Name = name;
 9         Age = age;
10     }
11 }

不足为奇情状下,C#的性情能够很好的匡助我们成功工作,比如下面的代码。在为属性赋值的时候,大家可以在随意地方为其赋值。可是并没有一种像是字段一样的扬言且登时初步化的语法来简化默许值的设定。C#6为我们带来了这种新的语法,像是为字段赋值一样为属性赋值。

我们也清楚,C#的性质实际上是多少个编写翻译器自动生成的私家字段、get_xxx和set_xxx、一条元数据整合,比如上边的代码编写翻译后:

美高梅开户网址 1

<Name>k__BackingField字段的IL

1 .field private string '<Name>k__BackingField'
2 .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
3 .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )

代表二个个体字段,第壹行分别表示这么些活动是编写翻译器自动生成的,第三行代表该字段不显得在Debugger窗口中。

 

get_Name方法的IL:

 1 .method public hidebysig specialname instance string 
 2         get_Name() cil managed
 3 {
 4   .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
 5   // Code size       7 (0x7)
 6   .maxstack  8
 7   IL_0000:  ldarg.0
 8   IL_0001:  ldfld      string csharp6.Person::'<Name>k__BackingField'
 9   IL_0006:  ret
10 } // end of method Person::get_Name

那也是1个自动生成的不二法门。

 

set_Name方法的IL:

 1 .method private hidebysig specialname instance void 
 2         set_Name(string 'value') cil managed
 3 {
 4   .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
 5   // Code size       8 (0x8)
 6   .maxstack  8
 7   IL_0000:  ldarg.0
 8   IL_0001:  ldarg.1
 9   IL_0002:  stfld      string csharp6.Person::'<Name>k__BackingField'
10   IL_0007:  ret
11 } // end of method Person::set_Name

相同是一个自动生成的法子。

 

Name属性的IL:

1 .property instance string Name()
2 {
3   .get instance string csharp6.Person::get_Name()
4   .set instance void csharp6.Person::set_Name(string)
5 } // end of property Person::Name

代表Name属性由三个get方法和set方法结合。

0. 目录

C#6 猛增特色目录

.NET面试题解析(00)-开篇来探讨面试 &
种类小说索引

提交答案

2、特性比字段多了get/set访问器;字段是在内存中声称的二个内存空间,能够确切的积存值;属性像字段一样使用,却能够有自身的代码段,能赋值取值,是因为访问属性正是调用属性的get/set方法对字段实行取值赋值(只怕不操作字段);在MSDN上,建议字段作为类的私人住房变量使用private/protected修饰,属性则往往作为共有属性使用public修饰;字段的读取和操作都以向来操作内部存储器,属性是调用get/set访问器,所以字段比属性快。

3、规范的话,没有差距。分裂仅仅是一贯赋值先实施,构造函数赋值后实施。在风谲云诡的IL中间语言(C#代码先编写翻译成IL代码,然后才编写翻译成汇编语言)中,字段直接赋值和构造函数赋值是在同1个代码段中(构造函数中)的。

4、本条题材得以和上边的标题一道起来回答。构造函数作为实例化1个类的入口,是首先访问的。字段的第壹手赋值其实也是身处构造函数中执行的,所以才说一贯赋值和构造函数赋值没有分别。“只读”的限量只是由C#编写翻译器(CLTucson)维护的,小编认为全名应该称为“除构造函数外只读”越发规范,这是C#语法的条条框框记住就行(那是本来,直接赋值其实是坐落构造函数中开展赋值的,假如构造函数不能够赋值那只读字段没有值和没有声飞鹤样);

5、反射赋值的有关,NET面试题解析。这些题材又能够和方面包车型地铁标题关系起来共同回答。通过反射能够给自读字段赋值不过不或许给只读属性举办赋值(不信任的可以试一下)。对只读字段的赋值是因为绕过了C#编写翻译器(CL陆风X8)的只读突显,对只读属性赋值的话是依旧调用set访问器对字段实行赋值,因为从没set访问器所以同意后会报错。那么难题来了,那为何只读自动属性没有set访问器还足以在构造函数中赋值呢?其实只读自动属性在构造函数中展开赋值,实质上是对字段举办赋值,和属性的get/set访问器没有涉嫌。

6、区分是怎么样?上边从来强调自动属性,是因为电动属性和一般性属性不平等,比如只读普通属性(没有set访问器)不能在构造函数中赋值。在未曾电动属性此前,普通属性使用手续是率先声明一(Beingmate)个字段如_id,然后声喜宝(Beingmate)脾个性Id,在get和set访问器中做一些操作,这个操作半数以上是对字段_id的操作,可是有时和字段没有关系。普通属性能够像字段一样通过“.”的法子调用,但又像方法一致具有代码段(普通属性温素不开辟内存空间)。

但是C#3.0以往引入了自行属性,评释方式如public
int id { get; set; },C#6.0随后又有了public string FirstName { get;
set; } = “Jane”。自动属性肯定开辟了内部存款和储蓄器空间然后才有了电动属性的直接赋值。其实在类中声称自动属性会在编写翻译成IL中间语言中宣称贰个隐藏字段,然后生成隐藏字段的get/set方法,然后生成get/set访问器。那里可以表明为啥只读普通属性不恐怕在构造函数中赋值(和平素赋值)而只读自动属性能够在构造函数中赋值(和直接赋值),因为无论是直接赋值照旧在构造函数中赋值,生成的IL代码中的构造函数中,操作的都以隐藏字段,并没有访问属性的set访问器。(注意那里只是说的类中的自动属性,接口中也是能够有全自动属性的,不过接口的自发性属性并不会扭转隐藏字段只是概念get/set访问器)

2. 机关属性增强语法

 1 internal class Person
 2 {
 3     //声明读写属性、且初始化默认值
 4     public string Name { get; set; } = "blackheart";
 5 
 6     //声明只读属性、且初始化默认值
 7     public int Age { get; } = 1;
 8 
 9     //声明只读属性
10     public string Note { get; }
11 
12     public Person(string note)
13     {
14         //在构造器中为只读属性初始化默认值
15         Note = note;
16     }
17 
18     private void func1()
19     {
20         //error,只能在构造器中初始化
21         //Note = "123";
22         //Age = 1;
23         //可以修改,因为有set访问器
24         Name = "new name";
25     }
26 }

那种新语法会在没有set访问器的时候把潜伏的个人字段设置为只读字段(readonly
),只允许在评释的时候设置先河值或然在构造器里面赋值。看看IL:

美高梅开户网址 2

除非Name属性具有set_Name方法,而Age和Note属性则从未set访问器,且相应的村办字段棉被服装置为”initonly”,表示那是二个只读字段。

构造器方法,Name{get;set;}=”blackheart”和Age{get;}=1的起初化操作部分被转移到实例构造函数”.ctor”方法中。

 1 .method public hidebysig specialname rtspecialname 
 2         instance void  .ctor(string note) cil managed
 3 {
 4   // Code size       34 (0x22)
 5   .maxstack  8
 6   IL_0000:  ldarg.0
 7   IL_0001:  ldstr      "blackheart"
 8   IL_0006:  stfld      string csharp6.Person::'<Name>k__BackingField'
 9   IL_000b:  ldarg.0
10   IL_000c:  ldc.i4.1
11   IL_000d:  stfld      int32 csharp6.Person::'<Age>k__BackingField'
12   IL_0012:  ldarg.0
13   IL_0013:  call       instance void [mscorlib]System.Object::.ctor()
14   IL_0018:  nop
15   IL_0019:  nop
16   IL_001a:  ldarg.0
17   IL_001b:  ldarg.1
18   IL_001c:  stfld      string csharp6.Person::'<Note>k__BackingField'
19   IL_0021:  ret
20 } // end of method Person::.ctor

和事先的语法生成的代码能够说是平等的,均是生成为2个字段、get_xxx和set_xxx方法和相应的属性元数据,本质仍旧是编写翻译器的语法简化。

1. 老版本代码

 1 internal class Person
 2 {
 3     public string Name { get; private set; }
 4     public int Age { get; private set; }
 5 
 6     public Person(string name,int age)
 7     {
 8         Name = name;
 9         Age = age;
10     }
11 }

常备状态下,C#的质量能够很好的帮衬我们成功工作,比如上边的代码。在为属性赋值的时候,我们得以在自由地点为其赋值。可是并不曾一种像是字段一样的扬言且立刻初阶化的语法来简化默许值的设定。C#6为大家带来了那种新的语法,像是为字段赋值一样为属性赋值。

我们也掌握,C#的天性实际上是3个编写翻译器自动生成的村办字段、get_xxx和set_xxx、一条元数据整合,比如上边的代码编写翻译后:

美高梅开户网址 3

<Name>k__BackingField字段的IL

1 .field private string '<Name>k__BackingField'
2 .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
3 .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )

意味着三个私家字段,第①行分别表示这几个活动是编译器自动生成的,第一行代表该字段不显得在Debugger窗口中。

 

get_Name方法的IL:

 1 .method public hidebysig specialname instance string 
 2         get_Name() cil managed
 3 {
 4   .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
 5   // Code size       7 (0x7)
 6   .maxstack  8
 7   IL_0000:  ldarg.0
 8   IL_0001:  ldfld      string csharp6.Person::'<Name>k__BackingField'
 9   IL_0006:  ret
10 } // end of method Person::get_Name

那也是3个自动生成的点子。

 

set_Name方法的IL:

 1 .method private hidebysig specialname instance void 
 2         set_Name(string 'value') cil managed
 3 {
 4   .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
 5   // Code size       8 (0x8)
 6   .maxstack  8
 7   IL_0000:  ldarg.0
 8   IL_0001:  ldarg.1
 9   IL_0002:  stfld      string csharp6.Person::'<Name>k__BackingField'
10   IL_0007:  ret
11 } // end of method Person::set_Name

一致是一个自动生成的法门。

 

Name属性的IL:

1 .property instance string Name()
2 {
3   .get instance string csharp6.Person::get_Name()
4   .set instance void csharp6.Person::set_Name(string)
5 } // end of property Person::Name

代表Name属性由一个get方法和set方法结合。

弱小和鸠拙不是在世的阻碍,傲慢才是!——《三体》

始发解释

通过C#变动的IL中间语言代码可以清楚的更明了

    public class User
    {
        public int id = 0;
        public int age { get; set; } = 1;
        public User()
        {
            id = 2;
            age = 3;
        }
    }

美高梅开户网址 4美高梅开户网址 5

能够见到,自动属性会生成二个名称为 ‘<age>k__BackingField’
的隐藏私有字段+私有字段的get/set方法+属性代码段;

能够观察IL代码生成了User的构造函数
.ctor,ctor是构造函数(Constructor)。

任由直接赋值依旧构造函数赋值,都以在.ctor中实施的,并且操作的都是字段,自动属性的赋值操作的是隐藏字段。

  public interface IUser
  {
    int id { get; set; }
  }

美高梅开户网址 6

能够见到,接口中的自动属性并不曾成形隐藏字段。

3. 参考

C# Auto-property
enhancements

2. 机关属性增强语法

 1 internal class Person
 2 {
 3     //声明读写属性、且初始化默认值
 4     public string Name { get; set; } = "blackheart";
 5 
 6     //声明只读属性、且初始化默认值
 7     public int Age { get; } = 1;
 8 
 9     //声明只读属性
10     public string Note { get; }
11 
12     public Person(string note)
13     {
14         //在构造器中为只读属性初始化默认值
15         Note = note;
16     }
17 
18     private void func1()
19     {
20         //error,只能在构造器中初始化
21         //Note = "123";
22         //Age = 1;
23         //可以修改,因为有set访问器
24         Name = "new name";
25     }
26 }

那种新语法会在平昔不set访问器的时候把潜伏的私有字段设置为只读字段(readonly
),只允许在宣称的时候设置开始值恐怕在构造器里面赋值。看看IL:

美高梅开户网址 7

唯有Name属性具有set_Name方法,而Age和Note属性则尚未set访问器,且相应的个人字段被安装为”initonly”,表示那是三个只读字段。

构造器方法,Name{get;set;}=”blackheart”和Age{get;}=1的早先化操作部分被更换成实例构造函数”.ctor”方法中。

 1 .method public hidebysig specialname rtspecialname 
 2         instance void  .ctor(string note) cil managed
 3 {
 4   // Code size       34 (0x22)
 5   .maxstack  8
 6   IL_0000:  ldarg.0
 7   IL_0001:  ldstr      "blackheart"
 8   IL_0006:  stfld      string csharp6.Person::'<Name>k__BackingField'
 9   IL_000b:  ldarg.0
10   IL_000c:  ldc.i4.1
11   IL_000d:  stfld      int32 csharp6.Person::'<Age>k__BackingField'
12   IL_0012:  ldarg.0
13   IL_0013:  call       instance void [mscorlib]System.Object::.ctor()
14   IL_0018:  nop
15   IL_0019:  nop
16   IL_001a:  ldarg.0
17   IL_001b:  ldarg.1
18   IL_001c:  stfld      string csharp6.Person::'<Note>k__BackingField'
19   IL_0021:  ret
20 } // end of method Person::.ctor

和事先的语法生成的代码能够说是同样的,均是生成为一个字段、get_xxx和set_xxx方法和相应的属性元数据,本质依旧是编写翻译器的语法简化。

  常会面试标题:

  1. const和readonly有啥分别?

  2. 如何类型能够定义为常量?常量const有怎么着风险?

  3. 字段与品质有啥异同?

  4. 静态成员和非静态成员的差异?

  5. 机动属性有怎么着风险?

  6. 特点是怎么着?咋样行使?

  7. 下边包车型地铁代码输出什么结果?为啥?

    List acs = new List(5);
    for (int i = 0; i < 5; i++) {

     acs.Add(() => { Console.WriteLine(i); });
    

    }
    acs.ForEach(ac => ac());

  8. C#中的委托是什么?事件是还是不是一种委托?

其他验证

① 、上文中关系“反射能够给只读字段实行赋值可是不恐怕给只读属性进行赋值”。不能给只读属性进行赋值是因为从没set访问器。可是大家已经领会了足以给字段赋值,并且只读属性会生成隐藏字段,那大家是否能够透过给隐藏字段展开赋值直接达到给机关属性赋值的指标呢?答案是能够的!

定义User的只读自动属性

    public class User
    {
        public int age { get;  } = 1;
        public User()
        {
            age = 3;
        }
    }

控制台的反光赋值代码:

            var user = new User();
            try { typeof(User).GetProperty("age").SetValue(user, 9); }
            catch{    Console.WriteLine("只读属性赋值失败");}
            typeof(User).GetField("<age>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(user,9);
            Console.WriteLine(user.age);
            Console.Read();

运行

美高梅开户网址 8

二 、因为隐藏字段是私人住房的,所以取到隐藏字段供给  BindingFlags.NonPublic

③ 、只读自动属性表达不想被访问到那为啥还要给它赋值呢?那么些标题……做着玩,项目中本身认为也没有何样用到的火候……

3. 参考

C# Auto-property enhancements

] 5-自动属性增强, 0. 目录 C#6
剧增特色目录 1. 老版本代码 1 internal class Person 2 { 3 public string
Name { get ; private set ; } 4 public int Age { get ;…

  字段与本性的恩仇

美高梅开户网址 9  常量

常量的基本概念就不细说了,关于常量的几脾性子总计一下:

  • 常量的值必须在编写翻译时规定,简单说就是在概念是安装值,未来都不会被转移了,她是编写翻译常量。
  • 常量只可以用来简单的项目,因为常量值是要被编写翻译然后保留到程序集的元数据中,只帮忙基元类型,如int、char、string、bool、double等。
  • 常量在使用时,是把常量的值内联到IL代码中的,常量类似一个占位符,在编写翻译时被沟通掉了。就是那天个性导致常量的2个风险,便是不帮助跨程序集版本更新

至于常量不援救跨程序集版本更新,举个大约的事例来验证:

public class A
{
    public const int PORT = 10086;

    public virtual void Print()
    {
        Console.WriteLine(A.PORT);
    }
}

上边一段万分简单代码,其生产的IL代码如下,在动用常量变量的地点,把他的值拷过来了(把常量的值内联到使用的地点),与常量变量A.PO安德拉T没有关系了。借使A引用了B程序集(B.dll文件)中的一个常量,假使前面单独修改B程序集中的常量值,只是再也编写翻译了B,而没有编写翻译程序集A,就会出难题了,正是地点所说的不援救跨程序集版本更新。常量值更新后,全体应用该常量的代码都无法不再一次编写翻译,那是大家在使用常量时务要求注意的二个标题。

  • 不用任意使用常量,尤其是有也许转变的数额;
  • 毫不随便修改已定义好的常量值;

美高梅开户网址 10

美高梅开户网址 11 补充一下枚举的面目

随即上面的const说,其实枚举enum也有相近的难点,其来源于和const一样,看看代码你就驾驭了。下边包车型客车是四个简易的枚举定义,她的IL代码定义和const定义是一模一样同等的啊!枚举的成员定义和常量定义一样,由此枚举其实本质上就非常是三个常量集合。

public enum EnumType : int
{
    None=0,
    Int=1,
    String=2,
}

美高梅开户网址 12

美高梅开户网址 13 关于字段

字段本人没什么好说的,那里说贰个字段的内联初阶化题材呢,可能不难被忽视的八个小标题(可是好像也没怎么震慑),先看看二个不难的事例:

public class SomeType
{
    private int Age = 0;
    private DateTime StartTime = DateTime.Now;
    private string Name = "三体";
}

概念字段并早先化值,是一种很常见的代码编写习惯。但只顾了,看看IL代码结构,一行代码(定义字段+赋值)被拆成了两块,末了的赋值都在构造函数里推行的。

美高梅开户网址 14

那么难题来了,假如有七个构造函数,就如上边那样,有多数个构造函数,会造成在三个结构函数.ctor中再一次产生对字段赋值的IL代码,那就招致了不供给的代码膨胀。那一个其实也很好解决,在非默许构造函数后加1个“:this()”就OK了,恐怕展现的在构造函数里起先化字段。

public class SomeType
{
    private DateTime StartTime = DateTime.Now;

    public SomeType() { }

    public SomeType(string name)
    {                
    }
}

美高梅开户网址 15 属性的原形

个性是面向对象编程的基本概念,提供了对个体字段的造访封装,在C#中以get和set访问器方法实现对可读可写属性的操作,提供了辽阳和灵活的数码访问封装。我们看看属性的真相,首要手段依旧IL代码:

public class SomeType
{
    public int Index { get; set; }

    public SomeType() { }
}

美高梅开户网址 16

地方定义的天性Index被分为了多少个部分:

  • 自动生成的个人字段“<Index>k__BackingField”
  • 方法:get_Index(),获取字段值;
  • 方法:set_Index(int32 ‘value’),设置字段值;

为此能够说属性的本来面目依旧格局,使用面向对象的考虑把字段封装了须臾间。在概念属性时,大家可以自定义二个私有字段,也能够选用自行属性“{ get; set; }
”的简化语法方式。

选用机关属性时索要注意一点的是,私有字段是由编写翻译器自动命名的,是不受开发职员控制的。正因为这么些难点,曾经在品种开发中遇见2个之所以而发生的Bug:

style=”font-size: small;”>这些Bug是关于系列化的,有贰个类,定义很五个(自动)属性,那个类的音讯供给持久化到地头文件,当时使用了.NET自带的二进制系列化组件。后来因为一个必要变动,把内部叁个字段修改了弹指间,须求把电动属性改为友好取名的民用字段的品质,就像是上边实例这样。测试系列化到本地没有毛病,反系列化也没难题,但最后bug依然被测试出来了,难题在与反系列化以前(修改代码此前)的地面文件时,Index属性的值丢失了!!!

private int _Index;
public int Index
{
    get { return _Index; }
    set { _Index = value; }
}

因为属性的实质是办法+字段,真正的值是储存在字段上的,字段的名号变了,反类别化在此之前的文书时找不到对应字段了,导致值的不见!那也便是应用机关属性可能存在的危害。

  委托与事件

什么是寄托?简单的话,委托类似于 C或
C++中的函数指针,允许将艺术作为参数举办传递。

  • C#中的委托都继承自System.Delegate类型;

  • 寄托项指标宣示与办法签名类似,有再次回到值和参数;

  • 委托是一种可以打包命名(或匿名)方法的引用类型,把艺术当做指针传递,但委托是面向对象、类型安全的;

美高梅开户网址 17 委托的花果山真面目——是二个类

.NET中从不函数指针,方法也不或然传递,委托之所能够像3个家常引用类型一样传递,那是因为他精神上正是四个类。上边代码是叁个格外简单的自定义委托:

public delegate void ShowMessageHandler(string mes);

探访她生产的IL代码

美高梅开户网址 18

大家一行定义一个委托的代码,编写翻译器自动生成了一堆代码:

  • 编译器自动帮大家成立了1个类ShowMessageHandler,继承自System.MulticastDelegate(她又持续自System.Delegate),这是1个多播委托;
  • 委托类ShowMessageHandler中带有多少个法子,在那之中最要害的正是Invoke方法,签名和概念的法门签名一致;
  • 其余三个版本BeginInvoke和EndInvoke是异步执行版本;

因此,也就简单猜想,当大家调用委托的时候,其实正是调用委托对象的Invoke方法,能够印证一下,上面包车型客车调用代码会被编写翻译为对信托对象的Invoke方法调用:

private ShowMessageHandler ShowMessage;

//调用
this.ShowMessage("123");

美高梅开户网址 19

美高梅开户网址 20 .NET的闭包

闭包提供了一种恍若脚本语言函数式编制程序的省事、可以共享数据,但也设有部分隐患。

难题列表中的第9题,正是二个.NET的闭包的题材。

List<Action> acs = new List<Action>(5);
for (int i = 0; i < 5; i++)
{
    acs.Add(() => { Console.WriteLine(i); });
}
acs.ForEach(ac => ac()); // 输出了 5 5 5 5 5,全是5?这一定不是你想要的吧!这是为什么呢?

地点的代码中的Action便是.NET为大家定义好的2个无参数无再次回到值的委托,从上一节大家通晓委托实质是1个类,掌握这点是消除本题的显要。在那几个地点委托方法共享应用了多少个有的变量i,那生成的类会是什么的呢?看看IL代码:

美高梅开户网址 21

共享的一部分变量被升级为委托类的三个字段了:

  • 变量i的生命周期延长了;
  • for循环截止后字段i的值是5了;
  • 后边再度调用委托方法,肯定正是出口5了;

那该怎么样校正呢?相当的粗略,委托方法应用1个暂命运部变量就OK了,不共享数据:

List<Action> acss = new List<Action>(5);
for (int i = 0; i < 5; i++)
{
    int m = i;
    acss.Add(() => { Console.WriteLine(m); });
}
acss.ForEach(ac => ac()); // 输出了 0 1 2 3 4

关于原理,能够协调探索了!

  标题答案解析:

1. const和readonly有怎么着分别?

const关键字用来声称编写翻译时常量,readonly用来声称运营时常量。都足以标识一个常量,主要有以下分别:
壹 、初阶化地方不一样。const必须在宣称的还要赋值;readonly即能够在注脚处赋值,也得以在构造方法里赋值。
贰 、修饰对象分化。const即能够修饰类的字段,也足以修饰局地变量;readonly只好修饰类的字段

③ 、const是编译时常量,在编写翻译时规定该值,且值在编写翻译时被内联到代码中;readonly是运作时常量,在运作时规定该值。
④ 、const私下认可是静态的;而readonly如若设置成静态供给出示注脚 。
伍 、补助的档次时不一样,const只好修饰基元类型或值为null的其它引用类型;readonly能够是任何类型。

2. 什么样类型能够定义为常量?常量const有啥危害?

基元类型或值为null的别样引用类型,常量的高风险就是不援救跨程序集版本更新,常量值更新后,全部应用该常量的代码都不能够不另行编写翻译。

3. 字段与天性有怎样异同?

  • 属性提供了一发强劲的,灵活的功效来操作字段
  • 鉴于面向对象的封装性,字段一般不规划为Public
  • 属性允许在set和get中编辑代码
  • 属性允许控制set和get的可访问性,从而提供只读大概可读写的效益
    (逻辑上只写是尚未意思的)
  • 质量能够采纳override 和 new

4. 静态成员和非静态成员的分别?

  • 静态变量使用 static
    修饰符进行宣示,静态成员在加类的时候就被加载(上一篇中提到过,静态字段是随项目对象存放在Load
    Heap上的),通过类进行访问。
  • 不包罗static
    修饰符证明的变量称做非静态变量,在指标被实例化时创建,通过对象开始展览访问
  • 3个类的享有实例的一致静态变量都是同2个值,同1个类的区别实例的等同非静态变量能够是见仁见智的值
  • 静态函数的贯彻里不可能动用非静态成员,如非静态变量、非静态函数等。

5. 机动属性有啥风险?

因为电动属性的民用字段是由编写翻译器命名的,前期不宜随意修改,比如在类别化中会导致字段值丢失。

6. 特色是怎么着?怎么着使用?

天性与天性是全然不均等的多个概念,只是在名称上比较接近。Attribute个性便是事关了八个目的对象的一段配置音讯,本质上是3个类,其为目的元素提供关乎附加音信,那段附加音信囤积在dll内的元数据,它自个儿没什么意思。运营期以反射的章程来获得附加信息。使用格局能够参考:

7. 上面包车型地铁代码输出什么结果?为何?

List<Action> acs = new List<Action>(5);
for (int i = 0; i < 5; i++)
{
    acs.Add(() => { Console.WriteLine(i); });
}
acs.ForEach(ac => ac());

输出了 5 5 5 5
5,全是5!因为闭包中的共享变量i会被进步为委托对象的公家字段,生命周期延长了

8. C#中的委托是什么样?事件是或不是一种委托?

什么样是委托?简单来讲,委托类似于 C或
C++中的函数指针,允许将艺术作为参数举办传递。

  • C#中的委托都持续自System.Delegate类型;
  • 委托项指标扬言与措施签名类似,有再次来到值和参数;
  • 信托是一种能够打包命名(或匿名)方法的引用类型,把办法当做指针传递,但委托是面向对象、类型安全的;

美高梅开户网址,事件能够知晓为一种特有的寄托,事件之中是基于委托来贯彻的。

 

style=”font-family: 微软雅黑; font-size: small;”>版权全部,作品来源: style=”font-family: 微软雅黑; font-size: small;”>http://www.cnblogs.com/anding

style=”font-family: 微软雅黑; font-size: small;”>个人力量简单,本文内容仅供就学、商讨,欢迎指正、沟通。

.NET面试题解析(00)-开篇来探讨面试 &
连串小说索引

  参考资料:

书籍:CLR via C#

书本:你必须精通的.NET

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图