1 属性

这得先从属性开始说,为什么外部代码访问对象内部的数据用属性而不是直接访问呢,这样岂不是更方便一些,但是事实证明直接访问是不安全的。那么,Anders Hejlsberg(安德斯·海尔斯伯格)就为C#加入了属性这种语法糖,用起来跟数据成员一样,但实际上是 setXX()和getXX(),既安全又方便。

属性:是访问对象的首选方式,因为它们禁止外部代码访问对象内部的数据存储机制的实现。

public int MyIntProp
{
get
{
//property get code
}
set
{
//Proerty set code
}
}

1.1 get关键字

get块必须有一个属性的返回值,简单的属性一般与私有字段相关联,以控制对这个字段的访问,此时get块可以直接返回该字段的值,例如:

private int myInt;

public int myIntProp
{
  get
  {
    return myInt;
  }
  set
  {
    //Property set code.
  }
}

类外部的代码不能直接访问这个myInt字段,私有的,必须使用属性来访问该字段。

1.2 set关键字

set函数以类似的方法把一个值赋给字段。这里使用value表示用户提供的属性值:

private int myInt;
public int myIntProp
{
  get
  {
    return myInt;
  }
  set
  {
    myInt = value;
  }
}

value等于类似与属性相同的值,所以如果属性和字段使用相同的类型,就不必担心数据类型转换了。

这个简单的属性只能直接访问myInt字段。在对操作进行更多的控制的时候,属性的真正作用才能发挥出来,例如,使用下面的代码实现set块:

set
{
  if(value >= && value <= )
  myInt = value;
}

只用赋给属性的值在1~10之间,才会改myInt。此时,要做一个重要的设计选择:如果使用了无效值,该怎么办:

  • 什么也不做
  • 给字段赋默认值
  • 继续执行,就好像没有发生错误一样,但记录下来该事件,以备将来分析
  • 抛出异常

一般情况下,后面两个选择效果较好,选择哪个选项取决于如何使用类,以及给用户授予多少控制权。抛出异常给用户提供的控制权相当的大,例如:

set
{
  if(value >= && value <= )
    myInt = value;
  else
    throw (new ArgumentOutOfRangeException("myIntProp",value,"myIntProp must be assigned a value between 0 and 10."))
}

这可以在使用属性的代码中通过try...catch...finaly逻辑来处理。

注:属性可以使用virtual、override和abstract关键字,就像方法一样,但这几个关键字不能用于字段。最后,如上述,访问器可以有自己的访问性。

实例:

public class MyClass
{
public readonly string Name;
private int intVal; public int Val
{
  get
  {
  return intVal;
  }
  set
  {
    if (value >= && value <= )
      intVal = value;
    else
      throw (new ArgumentOutOfRangeException("Val",value,"Val must be assigned a value between 0 ang 10."));
  }
}
public override string ToString()
{
  return "Name:"+Name+"\nVal:"+Val;
}
private MyClass(): this("Default Name")
{ }
public MyClass(string newName)
{
  Name = newName;
  intVal = ;
}
} static void Main(string[] args)
{
  Console.WriteLine("Creating object myobj...");
  MyClass myObj = new MyClass("My Object");
  Console.WriteLine("myObj created.");
  for (int i = -; i <= ; i++ )
  {
    try
    {
      Console.WriteLine("\nAttempting to assign {0} to myObj.val...",i);
      myObj.Val = i;
      Console.WriteLine("Value {0} assigned to myObj.val.", myObj.Val);
    }
    catch(Exception e)
    {
      Console.WriteLine("Exception {0} throw.",e.GetType().FullName);
      Console.WriteLine("Message:\n\"{0}\"",e.Message);
    }
  }
  Console.WriteLine("\nOutputting myObj.ToString()...");
  Console.WriteLine(myObj.ToString());
  Console.WriteLine("myObj.ToString() Output.");
  Console.ReadKey();
}

Main()中的的代码创建并使用在MyClass.cs中定义的MyClass类的实例。实例化这个类必须使用非默认的构造函数来进行,因为MyClass类的默认构造函数是私有的。

Main()试着给myObj(MyClass的实例)的Val属性赋值。for循环在两次中赋值-1和0,try..catch...结构用于检测抛出的异常。把-1赋给属性时,会抛出System.ArgumentOutOfException类型的异常,catch块中的代码会把改异常的信息输出到控制台窗口中。在下一个循环中,值0成功的赋给了Val属性,通过这个属性再把值赋给私有字段intVal。

2 自动属性

但是呢,安德斯还是觉得代码太多,还应该在优化一下,就想出了自动属性。

自动属性。利用自动属性,可以用简化的语法声明属性,C#编译器会自动添加未键入的内容,具体而言,编译器会声明一个用于存储属性的私有字段,并在属性的get和set块中使用该字段(非常贴心),我们无需考虑细节。

public int MyIntProp

{
  get;
  set;
}

我们按照通常的方式定义属性的可访问性、类型和名称。但是没有给get和set块提供实现的代码。这些块的实现代码(和底层的字段)由编译器提供。

使用自动属性时,只能通过属性访问数据,不能通过底层的私有字段来访问,我们不知道底层私有字段的名称(该名称是编译期间定义的)。但这并不是一个真正意义上的限制,因为可以直接使用属性名。自动属性的唯一限制是他们必须包含get和set存储器,无法使用这种方法定义只读和只写属性。

3 对象初始化器

对象初始化器定义:初始化器分为对象初始化器和集合初始化器,此处指我们讲的是对象初始化器,

作用:用较少的代码创建一个新对象并为对象的若干属性和公共数据成员进行赋值。

谈到初始化器,先谈一下构造函数,构造从表面意思就知道这是用来构建类的(当然初始化一些成员也是属于构建的范围,但还有其他作用)

对象初始化过程:先定义类的属性,再实例化和初始化这个类。

定义类的属性用自动属性来定义,实例化和初始化这个类的一个对象实例就必须用C#里面的默认的无参构造函数来实现下段代码。

先看一个类定义:

public class Curry
{
public string MainIngredient { get; set; }
public string Style { get; set; }
public int Spiciness { get; set; }
}

这个类有3 个属性,用自动属性语法来定义。如果希望实例化和初始化这个类的一个对象实例,就必须执行如下几个语句:

  1. 第一种方式
Curry tastyCurry = new Curry();

tastyCurry.MainIngredient = "panir tikka";

tastyCurry.Style = "jalfrezi";

tastyCurry.Spiciness = ;

如果类定义中未包含构造函数,这段代码就使用C#编译器提供的默认无参数构造函数。这种方式还是有点复杂,应该还有比这个简单的,你猜对了。

2.第二种方式(去掉括号)

Curry tastyCurry=new Curry
{
tastyCurry.MainIngredient = "panir tikka", tastyCurry.Style = "jalfrezi", tastyCurry.Spiciness = ,
}

然后问题就来了,如果你有10个数据成员,实例化和初始化这个类的一个对象实例要写多少个?为了简化这个过程,安德斯又机灵了一下想到了更高级的方式,采用一个合适的非默认构造函数。

如下:

Class tastyCurry =new Curry(“panir tikka ”, “jalfrezi”,);

这段代码工作的很好,它会强制使用Curry类的代码使用这个构造函数,这将阻止前面默认使用无参构造函数的代码运行。

4 匿名类型

你以为这样就非常方便了么,只能说你太年轻,天外有天,人外有人,看看我们的题目,对了,就是它,我们的主角,匿名类型。

匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型。 类型名由编译器生成,并且不能在源代码级使用。 每个属性的类型由编译器推断。可通过使用 new 运算符和对象初始值创建匿名类型。

来,我们举个栗子。

以下示例显示了用两个名为 Amount 和 Message 的属性进行初始化的匿名类型。

var v = new { MainIngredient =“panir tikka ”, Style =“jalfrezi” Spiciness=};  

Console.WriteLine(v.MainIngredient + v.Style+v.Spiciness);  

看见了么,对,没错,就是这么简单。

备注:关于C# 的匿名类型为什么要限制属性为只读呢?

来自知乎网友的一段话我觉得说的挺好的。

其实匿名类型是C# 3.0引入的,C# 3.0引入的所有新特性基本都是为了实现LINQ这一伟大的语言特性。匿名类型是为了解决LINQ中选择部分字段以及多字段作为分组依据聚合或是多字段联接的问题的。所以,说白了匿名类型设计的目标就是元组。匿名类型本质上就是关系模型中的元组在C#里面的映射。元组显然是不可变的,匿名类型也没有必要设计成可变的来自找麻烦。

至此,匿名类型的由来就大致讲清楚了,主要是因为工程师要简便优化代码,匠心创作,匿名类型由此诞生。

参考文献:【c#入门经典第五版】【知乎

友情提示

作者:mhq_martin

博客园地址:http://www.cnblogs.com/mhq-martin/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

【C#复习总结】匿名类型由来的更多相关文章

  1. Entity Framework 6 Recipes 2nd Edition(11-5)译 -> 从”模型定义”函数返回一个匿名类型

    11-5. 从”模型定义”函数返回一个匿名类型 问题 想创建一个返回一个匿名类型的”模型定义”函数 解决方案 假设已有游客(Visitor) 预订(reservation)房间(hotel ) 的模型 ...

  2. Linq专题之提高编码效率—— 第二篇 神一样的匿名类型

    说起匿名类型,我们都知道这玩意都是为linq而生,而且匿名类型给我们带来的便利性大家在实战中应该都体会到了,特别适合于一次性使用,临时 使用这些场景,虽然说是匿名类型,也就是说是有类型的,只是匿名了而 ...

  3. 《精通C#》自定义类型转化-扩展方法-匿名类型-指针类型(11.3-11.6)

    1.类型转化在C#中有很多,常用的是int类型转string等,这些都有微软给我们定义好的,我们需要的时候直接调用就是了,这是值类型中的转化,有时候我们还会需要类类型(包括结构struct)的转化,还 ...

  4. 当匿名类型遇上Distinct

    首先定义一个简单类,并重写ToString方法. public class CommidityFilter { public string Property { get; set; } public ...

  5. C#简单问题,不简单的原理:不能局部定义自定义类型(不含匿名类型)

    今天在进行代码测试时发现,尝试在一个方法中定义一个委托,注意是定义一个委托,而不是声明一个委托变量,在编写的时候没有报错,VS也能智能提示,但在编译时却报语法不完整,缺少方括号,但实际查询并没有缺少, ...

  6. JavaScriptSerializer 中的匿名类型 转json

    二:JavaScriptSerializer 中的匿名类型 这个类型我想大家都清楚,不过性能更高的方式应该是用JsonConvert吧,但这个不是本篇讨论的话题,我们重点来看看匿名类型的Json序列化 ...

  7. 使用ExposedObject对Asp.net MVC中匿名类型的JsonResult做单元测试

    返回JsonResult是MVC中的常见返回值类型,而且简单方便的方式是结合匿名类型一起使用. 比如: public ActionResult PreviewEmail() { …… return J ...

  8. 15.C#回顾及匿名类型(八章8.1-8.5)

    今天的篇幅应该会很长,除了回顾前面学的一些,还有写一些关于匿名类型的相关知识,总体上对后续的学习很有帮助,学好了,后面更容易理解,不明白的,那就前面多翻几次,看多了总是会理解的.那么,进入正题吧. 自 ...

  9. 编写高质量代码改善C#程序的157个建议[匿名类型、Lambda、延迟求值和主动求值]

    前言 从.NET3.0开始,C#开始一直支持一个新特性:匿名类型.匿名类型由var.赋值运算符和一个非空初始值(或以new开头的初始化项)组成.匿名类型有如下基本特性: 1.既支持简单类型也支持复杂类 ...

随机推荐

  1. Mysql中给有记录的表添加唯一索引

    ALTER IGNORE TABLE neeqs ADD UNIQUE KEY `unique` (`seccode`, `enddate`, `f002v`);

  2. codeforces 761B Dasha and friends

    https://vjudge.net/problem/CodeForces-761B 题意: 有一个圆形跑道,上面有若干个障碍,分别给出两个人距离障碍的距离,问这两个人是否是在同一个跑道上跑步(我是这 ...

  3. linux centos-7.2-64bit 安装配置启动nginx

    1.安装依赖包yum -y install openssl openssl-develyum install pcre*yum install openssl*yum install zlib yum ...

  4. Hive函数:GROUPING SETS,GROUPING__ID,CUBE,ROLLUP

    参考:lxw大数据田地:http://lxw1234.com/archives/2015/04/193.htm 数据准备: CREATE EXTERNAL TABLE test_data ( mont ...

  5. Java:逐行读、写文件、文件目录过滤的用法

    import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.I ...

  6. 南京邮电大学java程序设计作业在线编程第一次作业

    王利国的"Java语言程序设计第1次作业(2018)"详细 作业结果详细 总分:100 选择题得分:40  1. Java语言中,基本数据类型一共有( )种. A.16 B.2 C ...

  7. JAVA数据库编程、JAVA XML解析技术

    JDBC概述 JDBC是JAVA中提供的数据库编程API curd :数据库增删改 链接字符串:String url = "mysql :/localhost :3306/jdbc/&quo ...

  8. 微信小程序:wx.request之post请求后端无法获取数据的问题

    前言:小程序的开发中总是踩到各种坑,看文档也不知所云: 例如当我们在写微信小程序接口时,method请求方式有POST和GET两种,为了数据安全,我们会偏向于使用POST请求方式访问服务器端: 问题: ...

  9. 使用NPOI-创建Excel

    这里简单的使用一下NPOI ,什么是NPOI? 既然你已经在需要使用了,就一定知道NPOI是干什么用的了. 开始正题吧. 我用控制台程序来给大家演示一下: 一.创建控制台程序 自行脑补 二.添加NPO ...

  10. c++简单线程池实现

    线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...