深入理解C#(一)

*第一章(大致了解C#各个版本的特性:数据类型)

产品/名称/价格的例子

C# 1实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Product
{
string name;
public string Name{ get { return name;} }

decimal price;
public decimal Price { get { return price; }}

public Product(string name,decimal price)
{
this.name=name;
this.price = price;
}

public static ArrayList GetSample()
{
ArrayList list = new ArrayList();
list.Add(new Prodect("west side",9.99m));
list.Add(new Prodect("Assassins",14.99m));
return list;
}

public override string ToString()
{
return string.Format("{0}: {1}",name,price);
}

存在以下问题:

  1. ArrayList 没有 提供 与其 内部 内容 有关 的 编译 时 信息。 不慎 在 GetSampleProducts 创建 的 列表 中 添加 一个 字符串 是 完全 有可能 的, 而 编译器 对此 没有 任何 反应。
    (例如list.Add("this is a string");编译器不能发现错误)
  2. 代码 中为 属性 提供 了 公共 的 取值 方法, 这 意味着 如果 添加 对应 的 赋值 方法, 那么 赋值 方法 也 必须 是 公共 的。
  3. 用于 创建 属性 和 变量 的 代码 很复杂—— 封装 一个 字符串 和 一个 十进制 数 应该 是一 个 十分 简单 的 任务, 不该 这么 复杂。

C# 2实现

1
2
3
4
5
6
public class Product
{
string name;
public string Name{
get { return name;}
private set { name=value;}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
decimal price;
public decimal Price { get { return price; }}

public Product(string name,decimal price)
{
this.name=name;
this.price = price;
}

public static List GetSample()
{
List<Product> list = new List();
list.Add(new Prodect("west side",9.99m));
list.Add(new Prodect("Assassins",14.99m));
return list;
}

public override string ToString()
{
return string.Format("{0}: {1}",name,price);
}

C# 2提出泛型
List list = new List();

且属性拥有私有赋值方法 private set { name=value;}

这样就解决了C# 1中前两个问题

C# 3实现

特性1:自动实现的属性和简化的初始化

1
2
3
public class Product
{
public string Name{ get; private set;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public decimal Price { get; private set; }

public Product(string name,decimal price)
{
Name=name;
Price = price;
}

Product() {}

public static List GetSample()
{
return new List{
new Prodect{ Name=”West Side",Price=9.99m},
new Prodect{Name="Assassins", Price=14.99m}
};
}

public override string ToString()
{
return string.Format("{0}: {1}",Name,Price);
}

用属性代替变量,删除了所有与变量关联的代码,在类中处处使用属性,增强了一致性。

有一个私有的无参构造函数,用于基于属性的初始化。

C# 4实现

为了移除易变形,使用只读属性

在调 用 构造 函数 时 指定 实 参 的 名称,
关于只读属性

  1. readonly是一个用于以下三种上下文的修饰符:

  2. 在字段定义中:readonly表示这个字段的实例化只能发生在<1>变量声明时<2>在所属类的构造器中

  3. 在只读段落(readonly struct)中:为一个struct加上readonly表示这个struct是不变的(immutable)。

  4. 在方法返回ref readonly中,表示这个方法返回一个reference,这个ref不可写

    using System.Collections.Generic;
    ​ public class Product
    ​ {
    ​ readonly string name;
    ​ public string Name{ get { return name;}

    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    readonly decimal price;	
    public decimal Price { get{return price;} }

    public Product(string name,decimal price)
    {
    this.name=name;
    this.price = price;
    }

    Product() {}

    public static List GetSample()
    {
    return new List{
    new Prodect{ name:"West Side",price:9.99m},
    new Prodect{name:"Assassins", price:14.99m}
    };
    }

    public override string ToString()
    {
    return string.Format("{0}: {1}",name,price);
    }

指定实参名称的好处是:在方法或构造函数包含多个参数时,使代码更清楚。另外可以不按顺序添加参数,而按照名称添加。这是C# 4为每个方法或构造函数自动添加的,直接使用。

小结一下:

除了用到readonly的时候,大部分时候选用C# 3的属性自动实现的特性,隐藏变量,在方法中始终使用属性,保持一致性。对于拥有多个复杂参数的函数或构造函数,用命名实参来调用方法。