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

0. 目录

C#6
增加产量特色目录

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

  体系小说目录地址:

建议难点

第3建议多少个难点:

一 、如何兑现和谐的流入框架?

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

③ 、字段和机动属性申明时的第叁手赋值和构造函数赋值有啥分裂?

④ 、为啥只读字段和只读自动属性(唯有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#的特性实际上是3个编写翻译器自动生成的个人字段、get_xxx和set_xxx、一条元数据整合,比如下边包车型地铁代码编写翻译后:

金沙注册送58 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

那也是多少个自动生成的章程。

 

【金沙注册送58】反射赋值的相干,NET面试题解析。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

一如既往是2个自动生成的艺术。

 

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

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

4、这些题材能够和下边包车型地铁标题一起起来回答。构造函数作为实例化贰个类的入口,是起头访问的。字段的直白赋值其实也是坐落构造函数中实施的,所以才说一向赋值和构造函数赋值没有分别。“只读”的范围只是由C#编写翻译器(CLSportage)维护的,小编以为全名应该叫做“除构造函数外只读”越发纯粹,那是C#语法的条条框框记住就行(那是本来,直接赋值其实是放在构造函数中进行赋值的,要是构造函数无法赋值那只读字段没有值和没有声可瑞康样);

5、其一题材又能够和方面包车型大巴题材关系起来共同回答。通过反射能够给自读字段赋值不过力不从心给只读属性举行赋值(不信任的可以试一下)。对只读字段的赋值是因为绕过了C#编写翻译器(CL汉兰达)的只读展现,对只读属性赋值的话是要么调用set访问器对字段实行赋值,因为从没set访问器所以同意后会报错。那么难题来了,那干什么只读自动属性没有set访问器还能在构造函数中赋值呢?其实只读自动属性在构造函数中展开赋值,实质上是对字段进行赋值,和总体性的get/set访问器没有涉及。

6、分裂是如何?上边一向强调自动属性,是因为电动属性和常见属性不均等,比如只读普通属性(没有set访问器)不能够在构造函数中赋值。在尚未机关属性此前,普通属性使用手续是率先声爱他美个字段如_id,然后声美素佳儿(Friso)个属性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:

金沙注册送58 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

和在此以前的语法生成的代码能够说是同一的,均是生成为八个字段、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、一条元数据整合,比如上边的代码编写翻译后:

金沙注册送58 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

那也是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属性由3个get方法和set方法结合。

弱小和无知不是生存的阻碍,傲慢才是!——《三体》

开端解释

通过C#变动的IL中间语言代码能够知晓的更明亮

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

金沙注册送58 4金沙注册送58 5

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

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

无论直接赋值依然构造函数赋值,都以在.ctor中履行的,并且操作的都是字段,自动属性的赋值操作的是隐藏字段。

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

金沙注册送58 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:

金沙注册送58 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

和前边的语法生成的代码能够说是相同的,均是生成为2个字段、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();

运行

金沙注册送58 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 ;…

  字段与质量的恩仇

金沙注册送58 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.PO奥迪Q3T没有涉嫌了。借使A引用了B程序集(B.dll文件)中的1个常量,如若前边单独修改B程序集中的常量值,只是再也编写翻译了B,而从不编写翻译程序集A,就会出难题了,正是地点所说的不援助跨程序集版本更新。常量值更新后,全体应用该常量的代码都不可能不另行编写翻译,那是大家在运用常量时必要求留意的二个标题。

  • 不要任意动用常量,尤其是有或然变化的多少;
  • 并非随便修改已定义好的常量值;

金沙注册送58 10

金沙注册送58 11 补充一下枚举的实质

继而上面包车型地铁const说,其实枚举enum也有近似的标题,其来源和const一样,看看代码你就清楚了。上边包车型客车是二个差不离的枚举定义,她的IL代码定义和const定义是同等同样的呦!枚举的分子定义和常量定义一样,由此枚举其实本质上就非凡是多少个常量集合。

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

金沙注册送58 12

金沙注册送58 13 关于字段

字段自己没什么好说的,那里说七个字段的内联初始化难题呢,或许不难被忽视的多个小标题(可是好像也没怎么震慑),先看看五个简短的例证:

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

概念字段并开端化值,是一种很广阔的代码编写习惯。但只顾了,看看IL代码结构,一行代码(定义字段+赋值)被拆成了两块,最终的赋值都在构造函数里举行的。

金沙注册送58 14

那正是说难题来了,假诺有多少个构造函数,就如上面那样,有过半个构造函数,会招致在几个协会函数.ctor中再次发生对字段赋值的IL代码,那就造成了不要求的代码膨胀。那一个实际上也很好化解,在非暗中同意构造函数后加三个“:this()”就OK了,也许展现的在构造函数里起先化字段。

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

    public SomeType() { }

    public SomeType(string name)
    {                
    }
}

金沙注册送58 15 属性的原形

品质是面向对象编制程序的基本概念,提供了对个体字段的拜会封装,在C#中以get和set访问器方法完成对可读可写属性的操作,提供了乌兰察布和灵活的多少访问封装。大家看看属性的本色,首要招数照旧IL代码:

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

    public SomeType() { }
}

金沙注册送58 16

上边定义的习性Index被分为了八个部分:

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

为此得以说属性的真面目依然措施,使用面向对象的盘算把字段封装了须臾间。在概念属性时,大家得以自定义2个私家字段,也足以运用机关属性“{ 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类型;

  • 信托项指标注脚与办法签名类似,有再次回到值和参数;

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

金沙注册送58 17 委托的天柱山真面目——是1个类

.NET中没有函数指针,方法也不恐怕传递,委托之所可以像一个一般性引用类型一样传递,那是因为他精神上就是三个类。上边代码是3个卓殊简单的自定义委托:

public delegate void ShowMessageHandler(string mes);

探望他生产的IL代码

金沙注册送58 18

咱俩一行定义多个信托的代码,编写翻译器自动生成了一堆代码:

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

因而,也就不难测度,当大家调用委托的时候,其实正是调用委托对象的Invoke方法,能够证Bellamy下,下边包车型大巴调用代码会被编写翻译为对信托对象的Invoke方法调用:

private ShowMessageHandler ShowMessage;

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

金沙注册送58 19

金沙注册送58 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为我们定义好的2个无参数无再次回到值的嘱托,从上一节我们了然委托实质是多少个类,通晓那一点是缓解本题的第③。在那几个地点委托方法共享应用了1个局地变量i,那生成的类会是何等的呢?看看IL代码:

金沙注册送58 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
    修饰符评释的变量称做非静态变量,在目的被实例化时创立,通过对象开始展览访问
  • 二个类的享有实例的一致静态变量都以同1个值,同叁个类的不如实例的等同非静态变量能够是见仁见智的值
  • 静态函数的兑现里不能够运用非静态成员,如非静态变量、非静态函数等。

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#金沙注册送58,中的委托是哪些?事件是或不是一种委托?

哪些是寄托?简单的讲,委托类似于 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地图