这是系列文章,是读"MS Press - MCTS Self-Paced Training Kit"的笔记,并把主要部分翻译成中文。
作者地址:http://www.cnblogs.com/nevernet (转载请保留)

Lesson 2: 使用引用类型

.NET Framework里面大部分类型都是引用类型,它们提供了极好的性能。

这节课之后,你将能够做:

  • 解释值类型和引用类型之间的不同之处.

  • 描述值类型和引用类型在传递值有何具体不同.

  • 列出内建的引用类型.

  • 说明你什么时候该用StringBuilder类型.

  • 创建数组并排序.

  • 打开、读取、写入和关闭文件.

  • 当异常发生时做出检测,并做出相应的响应.

估计本课时间: 40 minutes

什么是引用类型?

引用类型仅仅保存它们数据的地址(译者注:在内存里的地址), 就如通常所说的指针( pointer), 在栈( stack)中. 地址所指向的实际数据,其实是保存在名叫堆(heap)的某块内存中。运行环境通过垃圾回收机制(garbage collection)来管理使用的内存(the memory used by the heap)。

Best Practices—Garbage collection 

Garbage collection occurs only when needed or when triggered by a call to GC.Collect. Automatic garbage collection is optimized for applications where most instances are short-lived, except for those allocated at the beginning of the application. Following that design pattern will result in the best performance.

比较引用类型和值类型的行为

因为引用类型表示的是数据的地址,而不是数据本身,所以当把一个引用变量赋值给另外一个变量时,并没有复制数据,相反,仅仅是复制了引用(译者注:仅仅是复制了这个数据的地址)实际上,他们指向的数据都是一样的.

考虑下面的代码片段:

' VBStructure Numbers    Public val As Integer

    Public Sub New(ByVal _val As Integer)        val = _val    End Sub

    Public Overloads Overrides Function ToString() As String        Return val.ToString    End FunctionEnd Structure

// C#struct Numbers{    public int val;

    public Numbers(int _val)    { val = _val; }

    public override string ToString()    { return val.ToString(); }}

现在再考虑如下代码:

' VBDim n1 As Numbers = New Numbers(0)Dim n2 As Numbers = n1n1.val += 1n2.val += 2Console.WriteLine("n1 = {0}, n2 = {1}", n1, n2)

// C#Numbers n1 = new Numbers(0);Numbers n2 = n1;n1.val += 1;n2.val += 2;Console.WriteLine("n1 = {0}, n2 = {1}", n1, n2);

结果将显示 "n1 = 1, n2 = 2" ,因为它们是值类型,  但是,当你更改一个引用类型时, 将会更改所有该引用类型的副本(copies).

内建引用类型

在 .NET Framework里面,有大约2500种内建引用类型.  Table 1-3 列出了经常使用的类型

Table 1-3: Common Reference Types

Type

Use for

System.Object

The Object type is the most general type in the Framework. You can convert any type to System.Object, and you can rely on any type having ToString, GetType, and Equals members inherited from this type.

System.String

Text data.

System.Text.StringBuilder

Dynamic text data.

System.Array

Arrays of data. This is the base class for all arrays. Array declarations use language-specific array syntax.

System.IO.Stream

Buffer for file, device, and network I/O. This is an abstract base class; task-specific classes are derived from Stream.

System.Exception

Handling system and application-defined exceptions. Task-specific exceptions inherit from this type.

Strings and String Builders

这个两个类型不仅仅只是一个装数据的容器,也提供一些方法来操作数据,如下:

' VBDim s As String = "this is some text to search"s = s.Replace("search", "replace")Console.WriteLine(s)

// C#string s = "this is some text to search";s = s.Replace("search", "replace");Console.WriteLine(s);

在 .NET里面,System.String类型的变量是不可变的. 在运行的时候,如果赋值给一个string类型的变量,将复制一个新的值(与值类型的行为相同)

' VBDim s As String

s = "wombat"           ' "wombat"s += " kangaroo"       ' "wombat kangaroo"s += " wallaby"        ' "wombat kangaroo wallaby"s += " koala"          ' "wombat kangaroo wallaby koala"Console.WriteLine(s)

// C#string s;

s = "wombat";          // "wombat"s += " kangaroo";      // "wombat kangaroo"s += " wallaby";       // "wombat kangaroo wallaby"s += " koala";         // "wombat kangaroo wallaby koala"Console.WriteLine(s);

只有最后一个字符串有引用; 其它三个将被垃圾回收机制回收. 减少这样的操作(因为这种操作将多次调用垃圾回收机制),将有助于提高性能. 其它办法如下:

  • String类来合并、加入、格式化等方法把多个items变成一个.

  • StringBuilder类 创建动态字符串.

StringBuilder 方案提供了很大的灵活性.下面是使用StringBuilder的演示:

' VBDim sb As New System.Text.StringBuilder(30)sb.Append("wombat")     ' Build string.sb.Append(" kangaroo")sb.Append(" wallaby")sb.Append(" koala")Dim s as String = sb.ToString        ' Copy result to string.Console.WriteLine(s)

// C#System.Text.StringBuilder sb = new System.Text.StringBuilder(30);sb.Append("wombat");     // Build string.sb.Append(" kangaroo");sb.Append(" wallaby");sb.Append(" koala");string s = sb.ToString();       // Copy result to string.Console.WriteLine(s);

String class 来自 System.Object 运算符重载. Table 1-4 lists the operators the String class overrides.

Table 1-4: String Operators

Operator

Visual Basic

C#

Action on System.String

Addition

+ or &

+

Joins two strings to create a new string.

Equality

=

= =

Returns True if two strings have the same contents; False if they are different.

Inequality

<>

!=

The inverse of the equality operator.

Assignment

=

=

Copies the contents of one string into a new one. This causes strings to behave like value types, even though they are implemented as reference types.

如何创建数组并排序?

Arrays 使用 圆括号 (in Visual Basic) 或者方括号 (in C#) 来定义的:

' VB' Declare and initialize an array.Dim ar() As Integer = {3, 1, 2}

' Call a shared/static array method.Array.Sort(ar)

' Display the result.Console.WriteLine("{0}, {1}, {2}", ar(0), ar(1), ar(2))

// C#// Declare and initialize an array.int[] ar = { 3, 1, 2 };

// Call a shared/static array method.Array.Sort(ar);

// Display the result.Console.WriteLine("{0}, {1}, {2}", ar[0], ar[1], ar[2]);

如何使用 Streams?

Streams are another very common type because they are the means for reading from and writing to the disk and communicating across the network. The System.IO.Stream type is the base type for all task-specific stream types. Table 1-5 shows some of the most commonly used stream types. 另外, network streams 可以在 System.Network.Sockets 命名空间下找到,  encrypted streams 可以在System.Security.Cryptography 命名空间下找到。

Table 1-5: Common Stream Types

System.IO Type

Use to

FileStream

Create a base stream used to write to or read from a file

MemoryStream

Create a base stream used to write to or read from memory

StreamReader

Read data from the stream

StreamWriter

Write data to the stream

最简单的 stream 类是StreamReaderStreamWriter, 它们支持你对文本文件的读写. You can pass a filename as part of the constructor, enabling you to open a file with a single line of code. After you have processed a file, call the Close method so that the file does not remain locked. The following code, which requires the System.IO namespace, 下面代码演示如何读写文本文件:

' VB' Create and write to a text fileDim sw As StreamWriter = New StreamWriter("text.txt")sw.WriteLine("Hello, World!")sw.Close

' Read and display a text fileDim sr As StreamReader = New StreamReader("text.txt")Console.WriteLine(sr.ReadToEnd)sr.Close

// C#// Create and write to a text fileStreamWriter sw = new StreamWriter("text.txt");sw.WriteLine("Hello, World!");sw.Close();

// Read and display a text fileStreamReader sr = new StreamReader("text.txt");Console.WriteLine(sr.ReadToEnd());sr.Close();

More Info—Streams 

更多关于streams的信息, refer to Chapter 2, "Input/Output (I/O)."

如何抛出和捕捉 Exceptions

Exceptions are unexpected events that interrupt normal execution of an assembly. For example, if your assembly is reading a large text file from a removable disk and the user removes the disk, the runtime will throw an exception. This makes sense because there is no way your assembly could continue running.

Exceptions should never cause your assembly to fail completely.相反 , 你应该计划异常何时发生, 捕捉它们, 并对这个事件做出回应. In the preceding example, you could notify the user that the file was not available, and then await further instructions from the user. The following simplified code, which requires the System.IO namespace, demonstrates this:

' VBTry    Dim sr As StreamReader = New StreamReader("C:\boot.ini")    Console.WriteLine(sr.ReadToEnd)Catch ex As Exception    ' If there are any problems reading the file, display an error message    Console.WriteLine("Error reading file: " + ex.Message)End Try

// C#try{    StreamReader sr = new StreamReader(@"C:\boot.ini");    Console.WriteLine(sr.ReadToEnd());}

catch (Exception ex){    // If there are any problems reading the file, display an error message    Console.WriteLine("Error reading file: " + ex.Message);}

In the preceding example, if any type of error occurs—including a file not found error, insufficient privileges error, or an error during the reading of the file—processing continues within the Catch block. If no problems occur, the runtime skips the Catch block.

The base Exception class is very useful and contains an error message and other application data. In addition to the base Exception class, the Framework defines hundreds of exception classes to describe different types of events, all derived from System.SystemException. Additionally, you can define your own exceptions when you need to describe an event in more detail than allowed by the standard exception classes by deriving from System.ApplicationException.

拥有不同的异常类,允许你响应不同类型的错误. 运行环境将只执行第一个匹配异常类型的 Catch 块, however, so order Catch blocks from the most-specific to the least-specific. The following code sample displays different error messages for a file not found error, an insufficient privileges error, and any other type of error that might occur:

' VBTry    Dim sr As StreamReader = New StreamReader("text.txt")    Console.WriteLine(sr.ReadToEnd)Catch ex As System.IO.FileNotFoundException    Console.WriteLine("The file could not be found.")Catch ex As System.UnauthorizedAccessException    Console.WriteLine("You do not have sufficient permissions.")Catch ex As Exception    Console.WriteLine("Error reading file: " + ex.Message)End Try

This process is sometimes called filtering exceptions. Exception handling also supports a Finally block. The Finally block runs after the Try block and any Catch blocks have finished executing, whether or not an exception was thrown. Therefore, you should use a Finally block to close any streams or clean up any other objects that might be left open if an exception occurs. The following code sample closes the StreamReader object whether or not an exception occurs:

' VBDim sr As StreamReader = New StreamReader("text.txt")Try    Console.WriteLine(sr.ReadToEnd)

Catch ex As Exception    ' If there are any problems reading the file, display an error message    Console.WriteLine("Error reading file: " + ex.Message)Finally    ' Close the StreamReader, whether or not an exception occurred    sr.CloseEnd Try

// C#StreamReader sr = new StreamReader("text.txt");try{    Console.WriteLine(sr.ReadToEnd());}catch (Exception ex){    // If there are any problems reading the file, display an error message    Console.WriteLine("Error reading file: " + ex.Message);}finally{    // Close the StreamReader, whether or not an exception occurred    sr.Close();  //(译者注:其实把sr定义到try外面并不好,我们关闭sr时,可以加一个判断,如下:  //if(sr != null) sr.close();  //)}

Notice that the StreamReader declaration was moved outside the Try block in the preceding example. This is necessary because the Finally block cannot access variables that are declared within the Try block. This makes sense because depending on where an exception occurred, variable declarations within the Try block might not yet have been executed. To catch exceptions that occur both during and after the StreamReader declaration, use nested Try/Catch/Finally blocks.

Typically, all code except for simple variable declarations should occur within Try blocks. Robust error handling improves the user experience when problems occur and greatly simplifies debugging problems. However, exception handling does incur a slight performance penalty. To conserve space and focus on specific topics, sample code within this book will typically not include exception handling.

Working with Reference Types

练习 1: 区分类型是值类型还是引用类型

In this exercise, you will write a console application that displays whether objects are value or reference types.

  1. Using Visual Studio, create a new console application project. Name the project List-Value-Types.

  2. Create instances of the following classes:

    • SByte

    • Byte

    • Int16

    • Int32

    • Int64

    • String

    • Exception

    The following code demonstrates this:

    ' VBDim a As SByte = 0Dim b As Byte = 0Dim c As Int16 = 0Dim d As Int32 = 0Dim e As Int64 = 0Dim s As String = ""Dim ex As Exception = New Exception
    
    // C#SByte a = 0;Byte b =0;Int16 c = 0;Int32 d = 0;Int64 e = 0;string s = "";Exception ex = new Exception();

  3. Add each of the instances to a new object array, as the following code demonstrates:

    ' VBDim types As Object() = {a, b, c, d, e, s, ex}
    
    // C#object[] types = { a, b, c, d, e, s, ex };
    

  4. Within a foreach loop, check the object.GetType().IsValueType property to determine whether the type is a value type. Display each type name and whether it is a value type or a reference type, as the following code demonstrates:

    ' VBFor Each o As Object In types    Dim type As String    If o.GetType.IsValueType Then        type = "Value type"    Else        type = "Reference Type"    End If    Console.WriteLine("{0}: {1}", o.GetType, type)Next
    
    // C#foreach ( object o in types ){    string type;    if (o.GetType().IsValueType)        type = "Value type";    else        type = "Reference Type";
    
        Console.WriteLine("{0}: {1}", o.GetType(), type);}

  5. Run the console application, and verify that each type matches your understanding.

练习 2: Work with Strings and Arrays

在这里练习里面,你将编写一个函数来排序字符串.

  1. Using Visual Studio, create a new console application project. Name the project SortString.

  2. Define a string. Then use the String.Split method to separate the string into an array of words. The following code demonstrates this:

    ' VBDim s As String = "Microsoft .NET Framework 2.0 Application Development Foundation"Dim sa As String() = s.Split(" ")
    
    // C#string s = "Microsoft .NET Framework 2.0 Application Development Foundation";string[] sa = s.Split(' ');

  3. Call the Array.Sort method to sort the array of words, as the following code demonstrates:

    ' VBArray.Sort(sa)
    
    // C#Array.Sort(sa);

  4. Call the String.Join method to convert the array of words back into a single string, and then write the string to the console. The following code sample demonstrates this:

    ' VBs = String.Join(" ", sa)Console.WriteLine(s)
    
    // C#s = string.Join(" ", sa);Console.WriteLine(s);

  5. Run the console application, and verify that it works correctly.

 

练习3: Work with Streams and Exceptions

Consider a scenario(情节) in which a coworker wrote a simple Windows Forms application to view text files. However, users complain that it is very temperamental(喜怒无常的). If the user mistypes the filename or if the file is not available for any reason, the application fails with an unhandled exception error. You must add exception handling to the application to display friendly error messages to users if a file is not available.

  1. Copy the Chapter01\Lesson2-ViewFile folder from the companion CD to your hard disk, and open either the C# version or the Visual Basic .NET version of the ViewFile project.

  2. Exceptions occur when users attempt to view a file. Therefore, edit the code that runs for the showButton.Click event. Add code to catch any type of exception that occurs, and display the error in a dialog box to the user. If an exception occurs after the TextReader object is initialized, you should close it whether or not an exception occurs. You will need two nested Try blocks: one to catch exceptions during the TextReader initialization, and a second one to catch exceptions when the file is read. The following code sample demonstrates this:

    ' VBTry    Dim tr As TextReader = New StreamReader(locationTextBox.Text)    Try        displayTextBox.Text = tr.ReadToEnd    Catch ex As Exception        MessageBox.Show(ex.Message)    Finally        tr.Close()    End TryCatch ex As Exception    MessageBox.Show(ex.Message)End Try
    
    // C#try{    TextReader tr = new StreamReader(locationTextBox.Text);    try    { displayTextBox.Text = tr.ReadToEnd(); }    catch (Exception ex)    { MessageBox.Show(ex.Message); }    finally    { tr.Close(); }}catch (Exception ex){ MessageBox.Show(ex.Message); }

  3. Run your application. First verify that it can successfully display a text file. Then provide an invalid filename, and verify that a message box appears when an invalid filename is provided.

  4. Next add overloaded exception handling to catch System.IO.FileNotFoundException and System.UnauthorizedAccessException. The following code sample demonstrates this:

    ' VBTry    Dim tr As TextReader = New StreamReader(locationTextBox.Text)    Try        displayTextBox.Text = tr.ReadToEnd    Catch ex As Exception        MessageBox.Show(ex.Message)    Finally        tr.Close()    End TryCatch ex As System.IO.FileNotFoundException    MessageBox.Show("Sorry, the file does not exist.")Catch ex As System.UnauthorizedAccessException    MessageBox.Show("Sorry, you lack sufficient privileges.")Catch ex As Exception    MessageBox.Show(ex.Message)End Try
    
    // C#try{    TextReader tr = new StreamReader(locationTextBox.Text);    try    { displayTextBox.Text = tr.ReadToEnd(); }    catch (Exception ex)    { MessageBox.Show(ex.Message); }    finally    { tr.Close(); }}catch (System.IO.FileNotFoundException ex){ MessageBox.Show("Sorry, the file does not exist."); }catch (System.UnauthorizedAccessException ex){ MessageBox.Show("Sorry, you lack sufficient privileges."); }catch (Exception ex){ MessageBox.Show(ex.Message); }

  5. Run your application again, and verify that it provides your new error message if an invalid filename is provided.

课程概要

  • 引用类型保存数据的地址而不是数据本身

  • 当你复制一个值类型时,这个值的副本已经建立了. 当你复制一个引用类型时, 仅仅复制了指针. 因此, 如果你复制了一个引用类型,并修改了这个副本, 那么这个副本和所有的原始数据都被修改了.

  • .NET Framework 包含了很多内建的引用类型,你可以直接使用,或者创建自己的引用类型.

  • Strings 是不可变的; 用StringBuilder 来创建动态的字符串.

  • 用streams 来读写 files, memory, 和 network.

  • Catch 来 过滤 exceptions . 在Finally 语句里面关闭所有资源。

课程复习

Answers 

Answers to these questions and explanations of why each answer choice is right or wrong are located in the "Answers" section at the end of the book.

1. 

Which of the following are reference types? (Choose all that apply.)

  1. Types declared Nullable

  2. String

  3. Exception

  4. All types derived from System.Object

2. 

What is the correct order for Catch clauses when handling different exception types?

  1. Order from most general to most specific.

  2. Order from most likely to least likely to occur.

  3. Order from most specific to most general.

  4. Order from least likely to most likely to occur.

3. 

When should you use the StringBuilder class instead of the String class?

  1. When building a string from shorter strings.

  2. When working with text data longer than 256 bytes.

  3. When you want to search and replace the contents of a string.

  4. When a string is a value type.

4. 

Why should you close and dispose of resources in a Finally block instead of a Catch block?

  1. It keeps you from having to repeat the operation in each Catch.

  2. Finally blocks run whether or not an exception occurs.

  3. The compiler throws an error if resources are not disposed of in the Finally block.

  4. You cannot dispose of resources in a Catch block.

Answers

1.

Correct Answers: B and C

  1. Incorrect: Types declared as Nullable can only be value types.

  2. Correct: Strings are reference types.

  3. Correct: Exceptions are reference types.

  4. Incorrect: Value types derive from System.Object, so not all derived types are reference types.

2.

Correct Answer: C

  1. Incorrect: You should order Catch clauses from most specific to most general.

  2. Incorrect: The first type that matches is caught and subsequent Catch clauses are skipped.

  3. Correct: The first type that matches is caught, and subsequent Catch clauses are skipped. Therefore, you should order Catch clauses from most specific to most general to enable you to catch errors that you have specific error-handling for, while still catching other exceptions with the more general Catch clauses.

  4. Incorrect: The first type that matches is caught and subsequent Catch clauses are skipped.

3.

Correct Answer: A

  1. Correct: Using the String type to construct a dynamic string can result in a lot of temporary strings in memory because the String type is immutable. Therefore, using the StringBuilder class is preferable.

  2. Incorrect: Strings are limited to 32,767 bytes, not 256 bytes.

  3. Incorrect: You can search and replace with a standard String class.

  4. Incorrect: Strings are never value types; they are reference types.

4.

Correct Answer: B

  1. Incorrect: While this statement is true, the real advantage of using a Finally block is that code is executed even if the runtime does not throw an exception. Code in a Catch block is executed only if an exception occurs.

  2. Correct: Use Finally blocks for code that should run whether or not an exception occurs.

  3. Incorrect: The compiler will not throw an error if you do not include a Finally block. Finally blocks are optional.

  4. Incorrect: You can dispose of resources in a Catch block. However, the code will run only if an exception occurs. Typically, you need to dispose of resources whether or not an exception occurs.

转载于:https://www.cnblogs.com/nevernet/archive/2008/09/17/1292386.html

Chapter 1: 使用引用类型相关推荐

  1. 《JavaScript高级程序设计》Chapter 5 引用类型

    Chapter 5 引用类型 使用表格进行归纳,对表格中某些内容会进行必要解释,并把解释放在表格下方.   Object类型 Array类型 Date类型 RegExp类型 Function类型 基本 ...

  2. swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)

    在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换.我们可以先看看官方文档的描述: Unlike other programming languages, Swift does ...

  3. 《C++ Templates》笔记 Chapter 12 Fundamentals in Depth-Chapter 13 Names in Templates

    文章目录 Chapter 12 Fundamentals in Depth 12.1 Parameterized Declarations 12.1.1 Virtual Member Function ...

  4. 引用和指针的区别都有什么_为什么要有指针和引用类型?

    --显然,我们能通过名字使用对象.然而在 C++ 中,大多数对象都"有身份":也就是说对象位于内存的某个地址中,如果我们知道对象的地址和类型,就能访问它--翻译自 Bjarne S ...

  5. JS引用类型(6)——基本包装类型1

    [6]基本包装类型 3个特殊的引用类型:Boolean.Number.String. 每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据. ...

  6. c# 垃圾回收是引用类型而言的

    c# 垃圾回收是引用类型而言的 转载于:https://www.cnblogs.com/C-CHERS/p/3646387.html

  7. JS基础类型和引用类型

    JS基础类型和引用类型脑图

  8. Swift 值类型和引用类型的内存管理

    1.内存分配 1.1 值类型的内存分配 在 Swift 中定长的值类型都是保存在栈上的,操作时不会涉及堆上的内存.变长的值类型(字符串.集合类型是可变长度的值类型)会分配堆内存. 这相当于一个 &qu ...

  9. 微软在C# 8中引入预览版可空引用类型

    微软已经为开发者提供了预览版的可空引用类型(Nullable Reference Type),想尝鲜的开发者可以尝试这个新特性,并提供反馈. \\ 预览版可空引用类型是Visual Studio 20 ...

最新文章

  1. 20分钟教你搞懂Git!
  2. docker image镜像的发布
  3. 湖南2021年计算机一级考试,2021年湖南计算机一级考试时间(4页)-原创力文档...
  4. OpencvSharp的踩坑之路
  5. 汇编 if else
  6. wait和notify使用例子
  7. 深入react技术栈(7):组件化实例:Tab栏组件
  8. 想尝试搭建图像识别系统?这里有一份TensorFlow速成教程
  9. 三种方法进行分水岭分割
  10. [C++]最大连续子序列乘积
  11. Fragment中获取Activity的Context
  12. 教学:四步利用PHP study小皮面板在vscode上编辑php并运行
  13. rar、zip、7z等压缩率的测试
  14. IEEE 754 32bit浮点标识
  15. ElasticSearch简介及ElasticSearch部署、原理和使用介绍
  16. 2.45GHz天线初始尺寸设定
  17. 互联网拓扑是怎样构成的?又代表了什么?
  18. MySQL8免安装版下载安装与配置(linux)
  19. LeetCode 101:和你一起你轻松刷题(C++)总篇章正在陆续更新
  20. 数据通信与网络(一)

热门文章

  1. Unity3D实践1:摄像机跟随
  2. 结构体符号重载(简单版+手动扩栈方法)
  3. [Python] 字典 items()方法:同时对字典的键和值进行遍历
  4. java生成和识别二维码
  5. hdu1247 Hat’s Words
  6. JavaScript中调皮的undefined
  7. datagrip连接oracle
  8. 根据日期字符串获取当天星期几问题
  9. Sqlite中文资料
  10. iOS常用第三方类库