特点与信托,构造函数赋值

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

0. 目录

C#6
增加产量特色目录

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

  体系文章目录地址:

建议难题

率先提议多少个难点:

① 、怎么着贯彻和谐的流入框架?

贰 、字段和活动属性的分别是什么?

三 、字段和机动属性申明时的一贯赋值和构造函数赋值有何样界别?

四 、为啥只读字段和只读自动属性(唯有get没有set访问器)都能够在构造函数中进行赋值?

五 、反射可以给只读字段或许只读属性进行赋值吗?

⑥ 、自动属性和普通属性的差异?

那一个题材是本身在试着写本人的流入完毕时遇见的难点。那么些难点应有在念书C#时的首节课就应该学到了,作者看网上还有人享受说她在面试时遇到面试官问为何只读字段和只读自动属性能够在构造函数中展开赋值,他从未答应上来,然后他写小说商量那几个题材,却没有得出3个分明的答案,实在心疼。网上有关只读属性某个是写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 )

意味着三个私人住房字段,第③行分别代表这些活动是编写翻译器自动生成的,第1行表示该字段不显得在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

那也是二个自动生成的方法。

 

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访问器;字段是在内部存款和储蓄器中宣示的3个内部存款和储蓄器空间,能够确切的储存值;属性像字段一样使用,却能够有友好的代码段,能赋值取值,是因为访问属性就是调用属性的get/set方法对字段实行取值赋值(可能不操作字段);在MSDN上,建议字段作为类的个体变量使用private/protected修饰,属性则反复作为共有属性使用public修饰;字段的读取和操作都以一贯操作内部存储器,属性是调用get/set访问器,所以字段比属性快。

3、精确来说,没有区分。差异仅仅是直接赋值先实行,构造函数赋值后实施。在变幻莫测的IL中间语言(C#亚洲必赢官网 ,代码先编写翻译成IL代码,然后才编写翻译成汇编语言)中,字段直接赋值和构造函数赋值是在同三个代码段中(构造函数中)的。

4、本条题材得以和方面包车型大巴标题一道起来回答。构造函数作为实例化贰个类的入口,是首先访问的。字段的第壹手赋值其实也是坐落构造函数中推行的,所以才说一贯赋值和构造函数赋值没有分别。“只读”的范围只是由C#编写翻译器(CL本田UR-V)维护的,作者以为全名应该称为“除构造函数外只读”特别可信,那是C#语法的规则记住就行(那是本来,直接赋值其实是身处构造函数中开始展览赋值的,倘若构造函数不能够赋值那只读字段没有值和没有声Bellamy样);

5、其一标题又足以和地点的难题挂钩起来共同回答。通过反射能够给自读字段赋值但是力不从心给只读属性实行赋值(不相信的能够试一下)。对只读字段的赋值是因为绕过了C#编写翻译器(CL昂科威)的只读展现,对只读属性赋值的话是依旧调用set访问器对字段进行赋值,因为尚未set访问器所以同意后会报错。那么难点来了,那为什么只读自动属性没有set访问器还足以在构造函数中赋值呢?其实只读自动属性在构造函数中开始展览赋值,实质上是对字段实行赋值,和天性的get/set访问器没有关联。

6、有别于是什么样?上边平昔强调自动属性,是因为电动属性和普通属性不雷同,比如只读普通属性(没有set访问器)不能够在构造函数中赋值。在没有自动属性在此以前,普通属性使用手续是首先声美素佳儿(Friso)个字段如_id,然后声美赞臣(Meadjohnson)性情质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

和事先的语法生成的代码能够说是同样的,均是生成为二个字段、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#的质量实际上是三个编写翻译器自动生成的私家字段、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 )

表示1个个体字段,第贰行分别表示这么些活动是编写翻译器自动生成的,第二行表示该字段不显示在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

那也是2个自动生成的措施。

 

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”,表示那是1个只读字段。

构造器方法,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代码中的,常量类似一个占位符,在编译时被调换掉了。正是以此特性导致常量的一个风险,就是不支持跨程序集版本更新

至于常量不扶助跨程序集版本更新,举个简单的事例来注脚:

public class A
{
    public const int PORT = 10086;

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

下面一段分外容易代码,其生产的IL代码如下,在采用常量变量的地点,把她的值拷过来了(把常量的值内联到使用的地点),与常量变量A.POHavalT没有关系了。倘若A引用了B程序集(B.dll文件)中的2个常量,假使前边单独修改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代码,那就招致了不要求的代码膨胀。那个其实也很好化解,在非暗许构造函数后加2个“: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’),设置字段值;

故此得以说属性的本来面目照旧艺术,使用面向对象的研究把字段封装了一下。在概念属性时,大家能够自定义3个私有字段,也足以行使机动属性“{ get; set; }
”的简化语法情势。

动用电动属性时需要小心一点的是,私有字段是由编写翻译器自动命名的,是不受开发人士控制的。正因为这一个难点,曾经在项目支出中遇见二个就此而发生的Bug:

style=”font-size: small;”>这么些Bug是关于体系化的,有一个类,定义很多少个(自动)属性,这几个类的音信要求持久化到当半夏件,当时利用了.NET自带的二进制种类化组件。后来因为贰个须要变动,把个中3个字段修改了须臾间,要求把自动属性改为友好取名的个人字段的习性,就像是上面实例那样。测试体系化到地点没不寻常,反系列化也没难点,但最终bug照旧被测试出来了,难题在与反体系化从前(修改代码之前)的地点文件时,Index属性的值丢失了!!!

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

因为属性的真相是格局+字段,真正的值是储存在字段上的,字段的名号变了,反体系化在此以前的公文时找不到对应字段了,导致值的遗失!那也即是行使自动属性可能存在的高危害。

  委托与事件

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

  • C#中的委托都一连自System.Delegate类型;

  • 委托项目标扬言与艺术签名类似,有再次回到值和参数;

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

亚洲必赢官网 17 委托的本质——是二个类

.NET中平素不函数指针,方法也不恐怕传递,委托之所可以像一个不乏先例引用类型一样传递,那是因为他精神上正是一个类。上面代码是二个卓殊简单的自定义委托:

public delegate void ShowMessageHandler(string mes);

看看他生产的IL代码

亚洲必赢官网 18

笔者们一行定义叁个委托的代码,编写翻译器自动生成了一堆代码:

  • 编写翻译器自动帮我们创造了叁个类ShowMessageHandler,继承自System.MulticastDelegate(她又继续自System.Delegate),那是多个多播委托;
  • 委托类ShowMessageHandler中包涵多少个主意,在那之中最重点的正是Invoke方法,签名和概念的主意签名一致;
  • 其余七个本子BeginInvoke和EndInvoke是异步执行版本;

因此,也就不难预计,当大家调用委托的时候,其实正是调用委托对象的Invoke方法,能够印证一下,上边包车型地铁调用代码会被编译为对信托对象的Invoke方法调用:

private ShowMessageHandler ShowMessage;

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

亚洲必赢官网 19

亚洲必赢官网 20 .NET的闭包

闭包提供了一种恍若脚本语言函数式编程的方便人民群众、能够共享数据,但也存在有的隐患。

标题列表中的第七题,正是一个.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为大家定义好的三个无参数无重返值的委托,从上一节我们清楚委托实质是八个类,明白那点是消除本题的根本。在那一个地方委托方法共享应用了一个局地变量i,那生成的类会是怎么的呢?看看IL代码:

亚洲必赢官网 21

共享的有些变量被升高为委托类的3个字段了:

  • 变量i的生命周期延长了;
  • for循环甘休后字段i的值是5了;
  • 背后再一次调用委托方法,肯定便是出口5了;

那该如何改进呢?很简单,委托方法应用贰个权且局地变量就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个值,同二个类的两样实例的同样非静态变量能够是见仁见智的值
  • 静态函数的达成里无法利用非静态成员,如非静态变量、非静态函数等。

5. 电动属性有何样危机?

因为机关属性的个人字段是由编写翻译器命名的,中期不宜随意改动,比如在体系化中会导致字段值丢失。

6. 风味是哪些?如何运用?

特点与脾性是一点一滴不平等的三个概念,只是在称呼上相比像样。Attribute性情正是涉及了1个对象对象的一段配置音讯,本质上是二个类,其为目的成分提供关乎附加新闻,这段附加新闻存款和储蓄在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地图