常量

常量是值从不变化的符号。定义常量符号时,它的值必须能在编译时确定。确定后,编译器将唱两只保存在程序集元数据中。使用const关键字声明常量。由于常量值从不变化,所以常量总是被视为类型定义的一部分。换言之,常量总是被视为静态成员,而不是实例成员。常量的值直接潜入代码,在运行时不需要为常量分配任何内存。

字段

字段是一种数据成员,其中容纳了一个值类型的实例或者一个对引用类型的引用。由于字段存储在动态类型中,所以它们的值在运行时才能获取。字段还解决了常量存在的版本控制问题。字段可以是任何数据类型。

CLR支持readonly字段和 read/write字段,大多数字段是read/write字段,意味着在代码执行过程中,字段值可多次改变,但readonly字段只能在构造器方法中写入。

提示:当某个字段是引用类型,并且该字段被标记为readonly时,不可改变的是引用,而非字段引用的对象。

public sealed class AType {
// InvalidChars must always refer to the same array object
public static readonly Char[] InvalidChars = new Char[] { 'A', 'B', 'C' };
} public sealed class AnotherType {
public static void M() {
// The lines below are legal, compile, and successfully
// change the characters in the InvalidChars array
//编译成功没什么问题
AType.InvalidChars[0] = 'X';
AType.InvalidChars[1] = 'Y';
AType.InvalidChars[2] = 'Z'; // The line below is illegal and will not compile because
// what InvalidChars refers to cannot be changed
// 非法的,无法通过编译
//AType.InvalidChars = new Char[] { 'X', 'Y', 'Z' };
}
}

方法

实例构造器和类

构造器是将类型的实例初始化为良好状态的特殊方法。构造器在方法定义源数据表中始终叫做.ctor(vs构造函数的代码段就是ctor),创建引用类型的实例时,首先为实例的数据字段分配内存,然后初始化对象的附加字段,最后调用类型的实例构造器来设置对象的初始状态。

构造引用类型的对象是,在调用实力构造器之前,为对象分配的内存总总是先被归零,没有被构造器显式重写的所有字段都保证获得0null

实例构造器永远不能被继承,一个类型可以定义多个实力构造器,每个构造器都必须有不同的签名。

C#用简单的语法在构造引用类型的实例时初始化类型定义中的字段

internal sealed class SomeType {
private Int32 m_x = 5;
}

SomeType的构造器先把5存到m_x,在调用基类的构造器。

如果有几个以初始化的实力字段和许多重载的构造器方法,可以创建单个构造器来执行这些公共的初始化,然后让其他构造器都显式调用这个公共的构造器,这样能减少代码。

internal sealed class SomeType {
// Do not explicitly initialize the fields here
private Int32 m_x;
private String m_s;
private Double m_d;
private Byte m_b; // This method MUST be called by all constructors.
private void SetFieldDefaults() {
m_x = 5;
m_s = "Hi there";
m_d = 3.14159;
m_b = 0xff;
} // This constructor sets all fields to their default.
public SomeType() {
SetFieldDefaults();
} // This constructor sets all fields to their default, then changes m_x.
public SomeType(Int32 x) {
SetFieldDefaults();
m_x = x;
} // This constructor sets all fields to their default, then changes m_s.
public SomeType(String s) {
SetFieldDefaults();
m_s = s;
} // This constructor sets all fields to their default, then changes m_x & m_s.
public SomeType(Int32 x, String s) {
SetFieldDefaults();
m_x = x;
m_s = s;
}
}

实例构造器和结构

CLR总是允许创建值类型的实例,并且没有办法阻止值类型的实例化。值类型其实并不需要定义构造器,但CLR确实允许为值类型定义构造器。但必须显式调用才能执行。结构不能包含显式的无参构造器。没有无参构造器,值类型的字段总是被初始化为0null

扩展方法

要想定义自己的扩展方法,只需要在第一个参数前面添加this关键字。

规则和原则

  • C#只支持扩展方法,不支持扩展属性、扩展事件、扩展操作符。
  • 扩展方法必须在非泛型的静态类中声明,类型没有限制,只有第一个参数前面能用this关键字标记
  • 编译器在查找扩展方法时,要求静态类文件本身必须必有文件作用域,扩展方法必须在顶级静态类中作用,不鞥你在嵌套类中定义
  • 多个静态类可以定义相同的扩展方法,编译器检测到多个扩展方法,会提示方法调用不明确
  • 扩展方法存在版本控制问题,将来Microsoft添加和你一样的扩展方法,程序就会有不同的行为。

来一个扩展方法栗子:

internal static class StringBuilderExtensions {
public static Int32 IndexOf(this StringBuilder sb, Char value) {
for (Int32 index = 0; index < sb.Length; index++)
if (sb[index] == value) return index;
return -1;
}
}

参数

可选参数和命名参数

private static Int32 s_n = 0;

public static void Go() {

ImplicitlyTypedLocalVariables();

  // 1. Same as: M(9, "A", default(DateTime), new Guid());
// 直接调用M
M(); // 2. Same as: M(8, "X", default(DateTime), new Guid());
// 前两个参数指定,后两个是默认值
M(8, "X"); // 3. Same as: M(5, "A", DateTime.Now, Guid.NewGuid());
// 使用明明参数指定值
M(5, guid: Guid.NewGuid(), dt: DateTime.Now); // 4. Same as: M(0, "1", default(DateTime), new Guid());
// s_n先传入0 ,然后加1,把1传入,再加1 ,此时s_n是 2
M(s_n++, s_n++.ToString()); // 5. Same as: String t1 = "2"; Int32 t2 = 3;
// M(t2, t1, default(DateTime), new Guid());
// 2传入 s。然后加1,传入x
M(s: (s_n++).ToString(), x: s_n++);
}
private static void M(Int32 x = 9, String s = "A",
DateTime dt = default(DateTime), Guid guid = new Guid()) { Console.WriteLine("x={0}, s={1}, dt={2}, guid={3}", x, s, dt, guid);
}

规则和原则

  • 可为方法、构造器方法和有参属性的参数指定默认值。
  • 有默认值的参数必须放在没有默认值的所有参数之后。换言之,一旦定义了有默认值的参数,它右边的所有参数也必须有默认值。
  • 默认值必须是编译时能确定的常量值
  • 不要重命名参数变量,否则任何顶用着已传参数名的方式传递实参代码也必须得修改
  • 如果方法从模块外部调用,更改参数的默认的默认值具有潜在的危险性
  • 如果参数用refout关键字进行了标识,就不能设置默认值

隐式类型的局部变量

var关键字的真正价值就是让程序员少打几个字。

以传引用的方式向方法传递参数

即C#中refout关键字。以前用的不做,现在看来得经常使用。

先看一下out的栗子

public static void Main()
{
Int32 X; //没有初始化
GetValue(out x); //
Console.WriteLine(x); //显式10
} private static void GetValue(out Int32 v)
{
v = 10; // 在这里面必须初始化
}

在看一个ref的栗子

public static void Main() {
Int32 x = 5; // x is 初始化的字段
AddVal(ref x); // x must be initialized.
Console.WriteLine(x); // Displays "15"
} private static void AddVal(ref Int32 v) {
v += 10; // This method can use the initialized value in v.这方法可以改变已初始化的值
}

为值类型使用outref,等同于以传值的方式传递引用类型。

暂时就介绍上面两种使用refout的方式。

向方法传递可变数量的参数

通过使用param关键字完成

private static Int32 Add(params Int32[] values) {
// NOTE: it is possible to pass the 'values'
// array to other methods if you want to. Int32 sum = 0;
for (Int32 x = 0; x < values.Length; x++)
sum += values[x];
return sum;
}
Console.WriteLine(Add(1, 2, 3, 4, 5));//显式15

参数和返回类型的设计规范

声明方法的参数类型时,应尽量指定最弱的类型,宁愿要结构也不要基类。而返回类型要声明为最强的类型


总结

今天的依然是非常无聊但却非常基础的文章,比如扩展方法refout默认参数等等这些都在实际编程中是经常用到的,必须要掌握牢固,今天一个微软亚洲研究院大数据系列讲座开课了,努力坚持学完。

CLR via C# 读书笔记---常量、字段、方法和参数的更多相关文章

  1. CLR via c#读书笔记五:方法

    注:书本第8章:方法 实例构造器和类(引用类型) 构造器方法在“方法定义元数据表”中始终叫做.ctor(constructor的简称). 构造引用类型的对象,在调用类型的实例构造器之前,为对象分配的内 ...

  2. 强化学习读书笔记 - 05 - 蒙特卡洛方法(Monte Carlo Methods)

    强化学习读书笔记 - 05 - 蒙特卡洛方法(Monte Carlo Methods) 学习笔记: Reinforcement Learning: An Introduction, Richard S ...

  3. clr via c#读书笔记五:常量和字段

    1.常量是值从不变化的符号.只能定义编译器识别的基元类型的常量.如:Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,Single,Dou ...

  4. 《C#图解教程》读书笔记之三:方法

    本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.方法那些事儿 (1)方法的结构:方法头—指定方法的特征,方法体—可执行代码的语句序列: (2)方法的调用:参 ...

  5. CLR via c#读书笔记八:泛型

    1.定义泛型类型或方法时,为类型指定的任何变量(比如T)都称为类型参数.使用泛型类型或方法时指定的具体数据类型称为类型实参. 2.System.Collections.Concurrent命名空间提供 ...

  6. [Clr via C#读书笔记]Cp15枚举和位标识

    Cp15枚举和位标识 枚举类型 本质是结构,符号名称-值:好处显而易见:System.Enum;值类型: 编译的时候,符号会转换为常量字段: 枚举支持很多方法和成员: 位标识bit flag 判断和设 ...

  7. CLR via c#读书笔记六:参数

    注:书本第9单参数 CLR默认所有方法参数都传值.引用本身是值引的,意味左方法能修改对象,而调用都能看到这些修改.值类型,传的是实例的一个副本,所以调用者不受影响. (和以前理解的不一样.默认都是传值 ...

  8. [Clr via C#读书笔记]Cp17委托

    Cp17委托 简单介绍 delegate回调函数机制,可以理解存储函数地址的变量类型: 类型安全: 引用类型支持逆变和协变: 回调 静态方法,实例方法 委托的本质 所有的委托都派生自System.Mu ...

  9. [Clr via C#读书笔记]Cp7常量和字段

    Cp7常量和字段 常量 常量在编译的时候必须确定,只能一编译器认定的基元类型.被视为静态,不需要static:直接嵌入IL中: 区别ReadOnly 只能在构造的时候初始化,内联初始化. 字段 数据成 ...

随机推荐

  1. ACM-东北大学程序设计竞赛-网络赛(2016.04.16)

    Problem: A Time limit: 1s    Mem limit: 64 MB    AC/Submission: 0/0    Discuss Back   Ranklist  Stat ...

  2. WebGIS开源方案中空间数据的入库、编辑、发布的操作流程

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 本开源方案的构架是:geoserver(服务器)+tomca ...

  3. DSO Framer Control Object 操作word文件

    <1>DSO Framer Control Object 实现加载word文件的不可编辑 axFramerControl1.Open(OldPath); this.axFramerCont ...

  4. 你真的会玩SQL吗?删除重复数据且只保留一条

    在网上看过一些解决方法 我在此给出的方法适用于无唯一ID的情形 表:TB_MACVideoAndPicture 字段只有2个:mac,content mac作为ID,正常情况下mac数据是唯一的,由于 ...

  5. Linux 学习笔记

    Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...

  6. jQuery-1.9.1源码分析系列(三) Sizzle选择器引擎——一些有用的Sizzle API

    说一下Sizzle中零碎的API.这些API有的被jQuery接管,直接使用jQuery.xxx就可以使用,有的没有被接管,如果要在jQuery中使用,使用方法是jQuery.find.xxx. 具体 ...

  7. Cocos2dx实现光影效果的两种方式

    Shader 和 RenderTexture 先贴上两张效果图 (Shader) (RenderTexture) 说一下实现的原因,因为项目中需要夜景,光影的效果.最初想到使用Shader来实现.实现 ...

  8. 无法解决 equal to 操作中 "SQL_Latin1_General_CP1_CI_AS" 和 "Chinese_PRC_CI_AS"

    无法解决 equal to 操作中 "SQL_Latin1_General_CP1_CI_AS" 和 "Chinese_PRC_CI_AS" 之间 2011-0 ...

  9. android Can't bind to local 86XX for debugger

    For some reason eclipse DDMS always gives the error 'Can't bind to local 86XX for debugger' every ti ...

  10. 【MVC拾遗】MVC的单元测试简单学习总结

    关于测试的必要性什么的已经在 重构与测试 里扯过了.倒也没必要说,写的代码多了自然就明白这个东西重要性. 当时说了坐等被推动去学习单元测试来着,然而等着被人推动的结果就是根本就没人来推你.o(∩_∩) ...