威尼斯人线上娱乐

性子与信托,自动属性增强

30 3月 , 2019  

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

0. 目录

C#6
新增特色目录

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

  类别小说目录地址:

建议难点

第②提议几个难点:

一 、怎样完结和谐的注入框架?

二 、字段和机关属性的界别是怎么样?

三 、字段和自动属性表明时的第1手赋值和构造函数赋值有啥分别?

肆 、为何只读字段和只读自动属性(唯有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 )

表示多个个体字段,第3行分别代表那几个活动是编写翻译器自动生成的,第壹行表示该字段不出示在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访问器;字段是在内部存款和储蓄器中注解的2个内部存储器空间,能够确切的储存值;属性像字段一样选用,却得以有友好的代码段,能赋值取值,是因为访问属性正是调用属性的get/set方法对字段实行取值赋值(也许不操作字段);在MSDN上,建议字段作为类的民用变量使用private/protected修饰,属性则往往作为共有属性使用public修饰;字段的读取和操作都以一直操作内部存款和储蓄器,属性是调用get/set访问器,所以字段比属性快。

3、标准来说,没有分别。分化仅仅是直接赋值先实施,构造函数赋值后进行。在扭转的IL中间语言(C#代码先编写翻译成IL代码,然后才编写翻译成汇编语言)中,字段直接赋值和构造函数赋值是在同贰个代码段中(构造函数中)的。

4、那个难题得以和方面包车型的士题材一起起来回答。构造函数作为实例化叁个类的进口,是初次访问的。字段的直白赋值其实也是位于构造函数中履行的,所以才说一贯赋值和构造函数赋值没有区别。“只读”的限定只是由C#编写翻译器(CL陆风X8)维护的,小编觉着全名应该称为“除构造函数外只读”更加纯粹,那是C#语法的规则记住就行(那是当然,直接赋值其实是放在构造函数中开始展览赋值的,假使构造函数不能够赋值那只读字段没有值和尚未声Bellamy(Bellamy)样);

5、本条难题又有什么不可和地点的难点联系起来共同回答。通过反射能够给自读字段赋值但是无法给只读属性实行赋值(不正视的能够试一下)。对只读字段的赋值是因为绕过了C#编写翻译器(CLENCORE)的只读展现,对只读属性赋值的话是照旧调用set访问器对字段进行赋值,因为没有set访问器所以同意后会报错。那么难点来了,那为啥只读自动属性没有set访问器还足以在构造函数中赋值呢?其实只读自动属性在构造函数中进行赋值,实质上是对字段实行赋值,和属性的get/set访问器没有涉嫌。

6、有别于是哪些?下面一贯强调自动属性,是因为机关属性和一般属性不雷同,比如只读普通属性(没有set访问器)不大概在构造函数中赋值。在尚未机关属性以前,普通属性使用手续是首先声圣元(Synutra)(Nutrilon)个字段如_id,然后声澳优(Ausnutria Hyproca)个属性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”,表示那是3个只读字段。

构造器方法,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#的性质实际上是二个编写翻译器自动生成的私家字段、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

那也是三个自动生成的主意。

 

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

能够看看,自动属性会生成1个称谓为 ‘<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

和在此以前的语法生成的代码能够说是同一的,均是生成为1个字段、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.PORT没有提到了。假设A引用了B程序集(B.dll文件)中的3个常量,假如后边单独修改B程序集中的常量值,只是再一次编写翻译了B,而从未编写翻译程序集A,就会出标题了,正是地点所说的不补助跨程序集版本更新。常量值更新后,全体应用该常量的代码都不能够不重新编写翻译,那是我们在运用常量时必要求留意的八个难点。

  • 永不随意动用常量,尤其是有恐怕变动的多寡;
  • 并非随便修改已定义好的常量值;

威尼斯人线上娱乐 10

威尼斯人线上娱乐 11 补充一下枚举的本来面目

接着上边的const说,其实枚举enum也有类似的标题,其根源和const一样,看看代码你就领会了。下边包车型大巴是2个粗略的枚举定义,她的IL代码定义和const定义是一律一样的哟!枚举的分子定义和常量定义一样,由此枚举其实本质上就万分是八个常量集合。

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

威尼斯人线上娱乐 12

威尼斯人线上娱乐 13 关于字段

字段本人没什么好说的,那里说二个字段的内联初阶化标题吗,恐怕不难被忽视的1个小难点(但是好像也没怎么影响),先看看2个简单的例子:

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

概念字段并早先化值,是一种很广泛的代码编写习惯。但注意了,看看IL代码结构,一行代码(定义字段+赋值)被拆成了两块,最后的赋值都在构造函数里实施的。

威尼斯人线上娱乐 14

那正是说难题来了,即使有多少个构造函数,就好像上面那样,有过半个构造函数,会促成在多少个组织函数.ctor中再一次发生对字段赋值的IL代码,那就造成了不须要的代码膨胀。那个其实也很好消除,在非暗许构造函数后加多少个“: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; }
”的简化语法方式。

使用自动属性时索要留意一点的是,私有字段是由编写翻译器自动命名的,是不受开发人员控制的。正因为这些标题,曾经在类型支出中蒙受三个为此而产生的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个平日引用类型一样传递,那是因为他精神上正是3个类。下边代码是1个格外不难的自定义委托:

public delegate void ShowMessageHandler(string mes);

看看她生产的IL代码

威尼斯人线上娱乐 18

我们一行定义贰个寄托的代码,编写翻译器自动生成了一堆代码:

  • 编译器自动帮大家创造了二个类ShowMessageHandler,继承自System.MulticastDelegate(她又再三再四自System.Delegate),那是三个多播委托;
  • 委托类ShowMessageHandler中蕴藏多少个章程,当中最重点的正是Invoke方法,签名和概念的办法签名一致;
  • 任何四个版本BeginInvoke和EndInvoke是异步执行版本;

为此,也就简单猜想,当大家调用委托的时候,其实正是调用委托对象的Invoke方法,能够证多美滋(Aptamil)下,下边包车型大巴调用代码会被编写翻译为对信托对象的Invoke方法调用:

private ShowMessageHandler ShowMessage;

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

威尼斯人线上娱乐 19

威尼斯人线上娱乐 20 .NET的闭包

闭包提供了一类别似脚本语言函数式编制程序的方便人民群众、能够共享数据,但也存在部分隐患。

题材列表中的第⑩题,正是3个.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为大家定义好的一个无参数无重返值的嘱托,从上一节我们知晓委托实质是三个类,领会那点是缓解本题的显要。在这么些地点委托方法共享应用了3个有的变量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个值,同一个类的不等实例的如出一辙非静态变量能够是见仁见智的值
  • 静态函数的贯彻里不能够动用非静态成员,如非静态变量、非静态函数等。

5. 自动属性有何危机?

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

6. 脾性是怎么着?怎么样利用?

特征与质量是截然差异等的七个概念,只是在名称上相比较像样。Attribute本性正是涉及了三个对象对象的一段配置信息,本质上是三个类,其为对象成分提供关乎附加新闻,那段附加音信存款和储蓄在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地图