C# 核心编程结构 II

1.方法和参数修饰符

  1).参数修饰符

参数修饰符

作用

 

参数传入函数的默认行为是按值传递。

如果一个参数没有用参数修饰符标记,则认为他将按照值传递(pass by value),这意味着被调用的方法收到原始数据的一份副本

public void Run(int number)

{

}

Out

 

输出的参数由被调用的方法赋值,因此他按照引用传递(pass by reference).如果被调用的方法没有给输出参数赋值,就会出现编译错误

int number=0;

public void Run(out int number)

{

number=1;//必须在方法里给其赋值,不然会编译出错

}

输出参数不需要在它们被传递给方法之前初始化,因为方法在退出之前必须为输出参数赋值。

ref

调用者赋初始值,并且可以由被调用的方法可选地重新赋值(因为数据是按引用窗体的).如果被调用的方法未给ref参数赋值,也不会有编译错误。

int number=0;

public void Run(ref int number)

{

number=1;//可以给其重新赋值,也可以对其不操作,具体看业务逻辑

}

引用参数必须在它们被传递给方法之前初始化,因为是在传递一个对已经存在变量的引用。

params

这个参数修饰符允许将一组可变数量的参数作为单独的逻辑参数进行传递,方法只能有一个parms修饰符,而且必须是方法的最后一个参数。事实上,你不会经常使用params修饰符,但要知道的是,基础类库中的许多方法都是用了这个c#语言特性。

void Run(params double[] list)

{
}

//调用方法

传递进一个以逗号分隔的double型数的列表

Run(4.0,3.0,5.7,64.1);

传递一个double型的数组

Double[] data={4.0,3.0,5.7,64.1}

Run(data);

2).定义可选参数

 随着NET4的发布,c#程序员现在可以创建包含可选参数的方法,这项技术允许方法的调用者不指定不必要的参数,而使用这些参数的默认值。

public void Run(string message,string owner=”说话”)

{

  Console.WriteLine(“提示信息:”+message);

  Console.WriteLine(“当前动作:”+owner);

}

Run(“只传第一个参数”);  

输出 :提示信息:只穿第一个参数

       说话

Run(“两个参数都传”,”跑步”);  

输出 :提示信息:两个参数都传

       跑步

特别注意:可选参数的默认值必须在编译的时候确定

例如可选参数 DateTime timeStamp=DateTime.Now 这个是错误的

3).使用命名参数法

   命名参数允许你在调用方法时以任意顺序指定参数的值。

public void Run(string message,string owner)

{

   }

Run(message:”第一个命名参数”,owner:”第二个命名参数”);

   在一个方法中既有命名参数又有位置参数,那么位置参数必须在命名参数之前

Run(”第一个位置参数”,owner:”第二个命名参数”);//正确

Run(message:”第一个命名参数”,”第二个位置参数”);//错误

   4).成员重载

   定义一组名字相同的成员时,如果他们的参数数量(或类型)不同,这样的成员就叫做被重载。

2.数组操作

标题

说明

数组初始化

使用new关键字的数组初始化int[] list=new int[]{1,2,3}

不使用new关键字的数组初始化 int[] list={1,2,3}

使用new关键字和大小(元素个数)的数组初始化

int[] list=new int[4]{1,2,3,4}

隐式类型本地数组

int[]数组:Var a=new[]{1,2,3,4}

double[]数组:var b=new[]{1,2,1.5}

string[]数组:var c=new[]{“hello”,null,”world”}

隐式数组不能添加多种数组元素。

Object数组

对象数组可以定义任何数组元素

object[] myObject=new object[]{“hello”,true,1,1.2}

多维数组

矩形数组:每一行长度相同的多维数组

int[,] myList;

myList=new int[6,6];表示数组有六个元素,每个元素都是一个6个元素的一维数组。

交错数组:交错数组包含一些内部数组,每一个都有各自的上界。

Int[][] myjc=new int[5][];

5:表示交错数组由五个一维数组组成

[5][]:后面的[]表示这五个一维数组的元素个数不一致。

System.Array基类

string[] list = new string[]{“1”,”2”,”3”}

循环输出list:1,2,3

Clear() 这个静态方法将数据中一系列元素设置为空值(值项0,对象引用null)

Array.Clear(list ,1,2)清除第一个元素,第二个元素

循环输出list:3,

CopyTo()这个方法用来将源数组中的元素复制到目标数组中。

Length 这个属性返回数组中项的个数

Rank 这个属性返回当前数组维数

Reverse() 这个静态方法反转一维数组的内容

Array.Reverse(list);

for(int i=0;list.length;i++)

{

 Console.WriteLine(list[i]+”,”);

}

循环输出:3,2,1,

Sort() 这个静态方法为内建类型的一维数组排序。如果数组中的元素实现了IComparer接口,我们就可以为自定义类型排序。

3.枚举类型

标题

说明

枚举格式

默认情况,第一个元素被设置为一个值0,其余的按照n+1递推:

enum EmpType

{

  Manager,//0

Grunt,//1

Contractor,//2

VicePresident//13

}

也可以设定第一个值(102),其余的按照n+1递推:

enum EmpType

{

  Manager=102,

Grunt,//103

Contractor,//104

VicePresident//105

}

枚举不一定是连续的,也不需要有唯一值:

enum EmpType

{

  Manager=102,

Grunt=1,

Contractor=3,

VicePresident=9

}

控制枚举的底层存储

默认情况下,用来保存枚举值的存储类型是System.Int32(C#int),当然我们也可以改成我们喜欢的类型:

创建一个对应byte的枚举:

enum EmpType:byte

{

 Manager=102,

Grunt=1,

Contractor=3,

VicePresident=9

}

声明枚举变量

声明枚举并且赋初始值:EmpType emp=EmpType.Manager;

为枚举变量赋值时,必须以枚举名(EmpType),来设置值(Manager),因为枚举是固定的一组名称/值对,将枚举变量设置为枚举类型没有定义的值是不合法的。

System.Enum类型

EmpType emp=EmpType.Manager;

静态方法Enum.GetUnderlyingType(emp.GetType())

或Enum.GetUnderlyingType(typeof(EmpType))

返回用于保存枚举类型值的数据类型。(对于EmpType就是System.Byte)

动态获取枚举的名称/值对:

获取枚举名称:emp.ToString();输出 Manager

获取枚举值只需要根据底层存储类型对枚举变量进行强制类型转换即可:(byte)emp

GetValues()静态方法:

这个方法返回System.Array的一个实例。数组中每一项都对应指定枚举的一个成员。

它会输出作为参数传入的任何枚举中的每一个名称/值对。

获传入参数的名称/值对:Array enumData=Enum.GetValues(emp.GetType());

for(int i=0;i<enumData.Length;i++)

{

  Console.WriteLine(“Name:{0},Value:{0:D}”+enumData.GetValue(i));

}

输出:Name:Manager,Value:102  

Name:Grunt,Value:1

Name:Contractor,Value:3

Name:VicePresident,Value:9

4.结构类型

标题

说明

结构说明

如果你有OOP背景,可以把结构看成是“轻量级的类类型”,因为结构提供了一种方式来定义这样一种类型,它们会支持封装,但不能用来构建一组相关类型。如果我们需要通过继承来构建一组相关类型,就需要使用类类型。

结构定义

struct Point

{

  private int X;//结构的字段

  private int Y;//结构的字段

  //将(X,Y)坐标增加1

  public void Increment()

{

   x++;y++;

}

}

说明:通常在类或结构中定义公共数据是一个不好的方式,我们最后使用私有数据,他可以使用公共属性来访问和改变。

创建结构变量

创建Point 结构变量,并且在调用其成员前为每一个公共字段数据赋值:

Point p2;

P2.X=10;

P2.Y=10;

P2.Increment();

如果我们在使用结构之前不为每一个公共字段数据赋值,就会收到一个编译错误。

使用c#的new 关键字来创建结构变量,它会调用结构默认的构造函数,默认构造函数会给每一个字段数据自动设置默认值:

Point p1=new Point();

P1.Increment();

还可以创建有参构造:

Point p1=new Point(10,10);

P1.Increment();

5.值类型和引用类型(引用自:http://www.cnblogs.com/jiajiayuan/archive/2011/09/23/2185966.html)

值类型与引用类型是很基础的知识,也有很多对此的介绍,如果想深入了解,张老师的博客讲解的很好,链接如下:
http://www.cnblogs.com/JimmyZhang/archive/2008/01/31/1059383.html
从概念上看,值类型直接存储其值,而引用类型存储对其值的引用。
我们知道,C#中的每一种类型要么是值类型,要么是引用类型。所以每个对象要么是值类型的实例,要么是引用类型的实例。
值类型和引用类型的基类
引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即直接继承System.ValueType。
作为所有类型的基类,System.Object提供了一组方法,这些方法在所有类型中都能找到,其中包含toString方法及clone等方法。
System.ValueType直接继承System.Object,即System.ValueType本身是一个类类型,而不是值类型;System.ValueType没有添加任何成员,但覆盖了所继承的一些方法,使其更适合于值类型。例如,ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

复制代码
    struct Program
{
static void Main(string[] args)
{
Program testType = new Program();

if (testType.GetType().IsValueType)
{
Console.WriteLine("{0} is value type.", testType.ToString());
}
Console.ReadLine();
}
}
复制代码

值类型
值类型的特性:
1).C#的所有值类型均隐式派生自System.ValueType。
   各个值类型及其基类:
   结构体:struct(直接派生于System.ValueType);
   数值类型:
   整型:
      short(System.Int16),ushort(System.UInt16),int(System.Int32),uint(System.UInt32),
      long(System.Int64),ulong(System.UInt64),
      sbyte(System.SByte的别名),byte(System.Byte),
    字符型:char(System.Char);
    浮点型:float(System.Single),double(System.Double);
    用于财务计算的高精度decimal型decimal(System.Decimal)。
    boolbool(System.Boolean的别名);
    枚举:enum(派生于System.Enum);
    可空类型(派生于System.Nullable泛型结构体,语法 T? 是 System.Nullable<T> 的简写,此处的 T 为值类型。)
2).每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。
例如:
int i = new int();
等价于:
Int32 i = new Int32();
等价于:
int i = 0;
等价于:
Int32 i = 0;
使用new运算符时,将调用特定类型的默认构造函数并对变量赋以默认值。在上例中,默认构造函数将值0赋给了i。
3).所有的值类型都是密封(seal)的,所以无法派生出新的值类型。
4).
值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
引用类型
引用类型的特性:
1).
C#的所有引用类型均隐式派生自System.object。
各个引用类型及其基类:
数组:(派生于System.Array)数组的元素,不管是引用类型还是值类型,都存储在托管堆上;
类:class(派生于System.Object);
接口:interface(接口不是一个“东西”,所以不存在派生于何处的问题。);
委托:delegate(派生于System.Delegate);
objectSystem.Object的别名);
字符串:string(System.String的别名)。
2).引用类型可以派生出新的类型。
3).引用类型可以包含null值。
4).
引用类型变量的赋值只复制对对象的引用,而不复制对象本身。
5).引用类型的对象总是在进程堆中分配(动态分配)。

值类型和引用类型的区别
  所有继承System.Value的类型都是值类型,其他类型都是引用类型。
  引用类型可以派生出新的类型,而值类型不能;
  引用类型存储在堆中,而值类型既可以存储在堆中也可以存储在栈中。
  引用类型可以包含null值,值类型不能(可空类型功能允许将 null 赋给值类型);
  引用类型变量的赋值只复制对对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。
  当比较两个值类型时,进行的是内容比较;而比较两个引用类型时,进行的是引用比较。
  值类型在内存管理方面具有更好的效率,并且不支持多态,适合用作存储数据的载体;引用类型支持多态,适合用于定义应用程序的行为。
Int[]是引用类型还是值类型
数组类型是一族类型,它们都继承System.Array,而System.Array继承自System.Object。所以所有的数组类型都是引用类型

猜你喜欢

转载自www.cnblogs.com/zhangliangliang/p/9120504.html
今日推荐