测绘程序设计C#版

测绘程序设计(C#)

第1章 C#与.NET Framework简介

在我们学习 C# 编程语言的基础构件块之前,让我们先看一下 C# 的最小的程序结构,以便作为接下来章节的参考。

C# Hello World 实例

一个 C# 程序主要包括以下部分:

  • 命名空间声明(Namespace declaration)
  • 一个 class
  • Class 方法
  • Class 属性
  • 一个 Main 方法
  • 语句(Statements)& 表达式(Expressions)
  • 注释 C# 文件的后缀为 .cs。 以下创建一个 test.cs 文件,文件包含了可以打印出 “Hello World” 的简单代码:
using System;
namespace HelloWorldApplication
{
   class HelloWorld
   {
      static void Main(string[] args)
      {
         /* 我的第一个 C# 程序*/
         Console.WriteLine("Hello World");
         Console.ReadKey();
      }
   }
}

当上面的代码被编译和执行时,它会产生下列结果:

Hello World

让我们看一下上面程序的各个部分: 程序的第一行 using System; - using 关键字用于在程序中包含 System 命名空间。 一个程序一般有多个 using 语句。 下一行是 namespace 声明。一个 namespace 里包含了一系列的类。HelloWorldApplication 命名空间包含了类 HelloWorld。 下一行是 class 声明。类 HelloWorld 包含了程序使用的数据和方法声明。类一般包含多个方法。方法定义了类的行为。在这里,HelloWorld 类只有一个 Main 方法。 下一行定义了 Main 方法,是所有 C# 程序的 入口点。Main 方法说明当执行时 类将做什么动作。 下一行 // 将会被编译器忽略,且它会在程序中添加额外的 注释。 Main 方法通过语句 Console.WriteLine(“Hello World”); 指定了它的行为。 WriteLine 是一个定义在 System 命名空间中的 Console 类的一个方法。该语句会在屏幕上显示消息 “Hello World”。

最后一行 Console.ReadKey(); 是针对 VS.NET 用户的。这使得程序会等待一个按键的动作,防止程序从 Visual Studio .NET 启动时屏幕会快速运行并关闭。 以下几点值得注意:

  • C# 是大小写敏感的。
  • 所有的语句和表达式必须以分号(;)结尾。
  • 程序的执行从 Main 方法开始。
  • 与 Java 不同的是,文件名可以不同于类的名称。

编译 & 执行 C# 程序

如果您使用 Visual Studio.Net 编译和执行 C# 程序,请按下面的步骤进行:

启动 Visual Studio。 在菜单栏上,选择 File -> New -> Project。 从模板中选择 Visual C#,然后选择 Windows。 选择 Console Application。 为您的项目制定一个名称,然后点击 OK 按钮。 新项目会出现在解决方案资源管理器(Solution Explorer)中。 在代码编辑器(Code Editor)中编写代码。 点击 Run 按钮或者按下 F5 键来运行程序。会出现一个命令提示符窗口(Command Prompt window),显示 Hello World。 您也可以使用命令行代替 Visual Studio IDE 来编译 C# 程序:

打开一个文本编辑器,添加上面提到的代码。 保存文件为 helloworld.cs。 打开命令提示符工具,定位到文件所保存的目录。 键入 csc helloworld.cs 并按下 enter 键来编译代码。 如果代码没有错误,命令提示符会进入下一行,并生成 helloworld.exe 可执行文件。 接下来,键入 helloworld 来执行程序。 您将看到 “Hello World” 打印在屏幕上。

第2章 C#语言基础

C# 基本语法 C# 是一种面向对象的编程语言。在面向对象的程序设计方法中,程序由各种相互交互的对象组成。相同种类的对象通常具有相同的类型,或者说,是在相同的 class 中。

例如,以 Rectangle(矩形)对象为例。它具有 length 和 width 属性。根据设计,它可能需要接受这些属性值、计算面积和显示细节。

让我们来看看一个 Rectangle(矩形)类的实现,并借此讨论 C# 的基本语法:

实例

using System;
namespace RectangleApplication
{
    class Rectangle
    {
        // 成员变量
        double length;
        double width;
        public void Acceptdetails()
        {
            length = 4.5;    
            width = 3.5;
        }
        public double GetArea()
        {
            return length * width;
        }
        public void Display()
        {
            Console.WriteLine("Length: {0}", length);
            Console.WriteLine("Width: {0}", width);
            Console.WriteLine("Area: {0}", GetArea());
        }
    }
   
    class ExecuteRectangle
    {
        static void Main(string[] args)
        {
            Rectangle r = new Rectangle();
            r.Acceptdetails();
            r.Display();
            Console.ReadLine();
        }
    }
}

尝试一下 » 当上面的代码被编译和执行时,它会产生下列结果:

Length: 4.5 Width: 3.5 Area: 15.75 using 关键字 在任何 C# 程序中的第一条语句都是:

using System; using 关键字用于在程序中包含命名空间。一个程序可以包含多个 using 语句。

class 关键字 class 关键字用于声明一个类。

C# 中的注释 注释是用于解释代码。编译器会忽略注释的条目。在 C# 程序中,多行注释以 /* 开始,并以字符 */ 终止,如下所示:

/* 这个程序演示 C# 的注释 使用 */ 单行注释是用 // 符号表示。例如:

// 这一行是注释 成员变量 变量是类的属性或数据成员,用于存储数据。在上面的程序中,Rectangle 类有两个成员变量,名为 length 和 width。

成员函数 函数是一系列执行指定任务的语句。类的成员函数是在类内声明的。我们举例的类 Rectangle 包含了三个成员函数: AcceptDetails、GetArea 和 Display。

实例化一个类 在上面的程序中,类 ExecuteRectangle 是一个包含 Main() 方法和实例化 Rectangle 类的类。

标识符 标识符是用来识别类、变量、函数或任何其它用户定义的项目。在 C# 中,类的命名必须遵循如下基本规则:

标识符必须以字母、下划线或 @ 开头,后面可以跟一系列的字母、数字( 0 - 9 )、下划线( _ )、@。 标识符中的第一个字符不能是数字。 标识符必须不包含任何嵌入的空格或符号,比如 ? - +! # % ^ & * ( ) [ ] { } . ; : " ’ / \。 标识符不能是 C# 关键字。除非它们有一个 @ 前缀。 例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字。 标识符必须区分大小写。大写字母和小写字母被认为是不同的字母。 不能与C#的类库名称相同。 C# 关键字 关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符,但是,如果您想使用这些关键字作为标识符,可以在关键字前面加上 @ 字符作为前缀。

在 C# 中,有些关键字在代码的上下文中有特殊的意义,如 get 和 set,这些被称为上下文关键字(contextual keywords)。

下表列出了 C# 中的保留关键字(Reserved Keywords)和上下文关键字(Contextual Keywords):

第 章 数据类型 在 C# 中,变量分为以下几种类型:

值类型(Value types) 引用类型(Reference types) 指针类型(Pointer types)

表达式与运算符

表达式

运算符

算数运算符

赋值运算符

关系运算符

逻辑运算符

其他运算符

  • new 运算符

第 章 C# 方法(函数)

一个方法是把一些相关的语句组织在一起,用来执行一个任务的语句块。每一个 C# 程序至少有一个带有 Main 方法的类。

要使用一个方法,您需要:

定义方法 调用方法

C# 中定义方法

当定义一个方法时,从根本上说是在声明它的结构的元素。在 C# 中,定义方法的语法如下:

(Parameter List) { Method Body } 下面是方法的各个元素:

Access Specifier:访问修饰符,这个决定了变量或方法对于另一个类的可见性。 Return type:返回类型,一个方法可以返回一个值。返回类型是方法返回的值的数据类型。如果方法不返回任何值,则返回类型为 void。 Method name:方法名称,是一个唯一的标识符,且是大小写敏感的。它不能与类中声明的其他标识符相同。 Parameter list:参数列表,使用圆括号括起来,该参数是用来传递和接收方法的数据。参数列表是指方法的参数类型、顺序和数量。参数是可选的,也就是说,一个方法可能不包含参数。 Method body:方法主体,包含了完成任务所需的指令集。 实例 下面的代码片段显示一个函数 FindMax,它接受两个整数值,并返回两个中的较大值。它有 public 访问修饰符,所以它可以使用类的实例从类的外部进行访问。

实例

class NumberManipulator
{
   public int FindMax(int num1, int num2)
   {
      /* 局部变量声明 */
      int result;

      if (num1 > num2)
         result = num1;
      else
         result = num2;

      return result;
   }
   ...
}

C# 中调用方法 您可以使用方法名调用方法。下面的实例演示了这点:

实例 using System;

namespace CalculatorApplication { class NumberManipulator { public int FindMax(int num1, int num2) { /* 局部变量声明 */ int result;

     if (num1 > num2)
        result = num1;
     else
        result = num2;

     return result;
  }
  static void Main(string[] args)
  {
     /* 局部变量定义 */
     int a = 100;
     int b = 200;
     int ret;
     NumberManipulator n = new NumberManipulator();

     //调用 FindMax 方法
     ret = n.FindMax(a, b);
     Console.WriteLine("最大值是: {0}", ret );
     Console.ReadLine();
  }

} } 当上面的代码被编译和执行时,它会产生下列结果:

最大值是: 200 您也可以使用类的实例从另一个类中调用其他类的公有方法。例如,方法 FindMax 属于 NumberManipulator 类,您可以从另一个类 Test 中调用它。

实例 using System;

namespace CalculatorApplication { class NumberManipulator { public int FindMax(int num1, int num2) { /* 局部变量声明 */ int result;

        if (num1 > num2)
            result = num1;
        else
            result = num2;

        return result;
    }
}
class Test
{
    static void Main(string[] args)
    {
        /* 局部变量定义 */
        int a = 100;
        int b = 200;
        int ret;
        NumberManipulator n = new NumberManipulator();
        //调用 FindMax 方法
        ret = n.FindMax(a, b);
        Console.WriteLine("最大值是: {0}", ret );
        Console.ReadLine();

    }
}

} 当上面的代码被编译和执行时,它会产生下列结果:

最大值是: 200 递归方法调用 一个方法可以自我调用。这就是所谓的 递归。下面的实例使用递归函数计算一个数的阶乘:

实例 using System;

namespace CalculatorApplication { class NumberManipulator { public int factorial(int num) { /* 局部变量定义 */ int result;

        if (num == 1)
        {
            return 1;
        }
        else
        {
            result = factorial(num - 1) * num;
            return result;
        }
    }

    static void Main(string[] args)
    {
        NumberManipulator n = new NumberManipulator();
        //调用 factorial 方法
        Console.WriteLine("6 的阶乘是: {0}", n.factorial(6));
        Console.WriteLine("7 的阶乘是: {0}", n.factorial(7));
        Console.WriteLine("8 的阶乘是: {0}", n.factorial(8));
        Console.ReadLine();

    }
}

} 当上面的代码被编译和执行时,它会产生下列结果:

6 的阶乘是: 720 7 的阶乘是: 5040 8 的阶乘是: 40320 参数传递 当调用带有参数的方法时,您需要向方法传递参数。在 C# 中,有三种向方法传递参数的方式:

C# 结构体(Struct)

在 C# 中,结构体(struct)是一种值类型(value type),用于组织和存储相关数据。

在 C# 中,结构体是值类型数据结构,这样使得一个单一变量可以存储各种数据类型的相关数据。

struct 关键字用于创建结构体。

结构体是用来代表一个记录,假设您想跟踪图书馆中书的动态,您可能想跟踪每本书的以下属性:

Title Author Subject Book ID 定义结构体 为了定义一个结构体,您必须使用 struct 语句。

struct 语句为程序定义了一个带有多个成员的新的数据类型。

例如,您可以按照如下的方式声明 Book 结构:

struct Books { public string title; public string author; public string subject; public int book_id; };
下面的程序演示了结构的用法:

实例 using System; using System.Text;

struct Books { public string title; public string author; public string subject; public int book_id; };

public class testStructure { public static void Main(string[] args) {

  Books Book1;        /* 声明 Book1,类型为 Books */
  Books Book2;        /* 声明 Book2,类型为 Books */

  /* book 1 详述 */
  Book1.title = "C Programming";
  Book1.author = "Nuha Ali";
  Book1.subject = "C Programming Tutorial";
  Book1.book_id = 6495407;

  /* book 2 详述 */
  Book2.title = "Telecom Billing";
  Book2.author = "Zara Ali";
  Book2.subject =  "Telecom Billing Tutorial";
  Book2.book_id = 6495700;

  /* 打印 Book1 信息 */
  Console.WriteLine( "Book 1 title : {0}", Book1.title);
  Console.WriteLine("Book 1 author : {0}", Book1.author);
  Console.WriteLine("Book 1 subject : {0}", Book1.subject);
  Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);

  /* 打印 Book2 信息 */
  Console.WriteLine("Book 2 title : {0}", Book2.title);
  Console.WriteLine("Book 2 author : {0}", Book2.author);
  Console.WriteLine("Book 2 subject : {0}", Book2.subject);
  Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);      

  Console.ReadKey();

} } 当上面的代码被编译和执行时,它会产生下列结果:

Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700 C# 结构的特点 结构提供了一种轻量级的数据类型,适用于表示简单的数据结构,具有较好的性能特性和值语义:

结构可带有方法、字段、索引、属性、运算符方法和事件,适用于表示轻量级数据的情况,如坐标、范围、日期、时间等。 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义无参构造函数。无参构造函数(默认)是自动定义的,且不能被改变。 与类不同,结构不能继承其他的结构或类。 结构不能作为其他结构或类的基础结构。 结构可实现一个或多个接口。 结构成员不能指定为 abstract、virtual 或 protected。 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。 结构变量通常分配在栈上,这使得它们的创建和销毁速度更快。但是,如果将结构用作类的字段,且这个类是引用类型,那么结构将存储在堆上。 结构默认情况下是可变的,这意味着你可以修改它们的字段。但是,如果结构定义为只读,那么它的字段将是不可变的。 类 vs 结构 类和结构在设计和使用时有不同的考虑因素,类适合表示复杂的对象和行为,支持继承和多态性,而结构则更适合表示轻量级数据和值类型,以提高性能并避免引用的管理开销。

类和结构有以下几个基本的不同点:

值类型 vs 引用类型:

结构是值类型(Value Type): 结构是值类型,它们在栈上分配内存,而不是在堆上。当将结构实例传递给方法或赋值给另一个变量时,将复制整个结构的内容。 类是引用类型(Reference Type): 类是引用类型,它们在堆上分配内存。当将类实例传递给方法或赋值给另一个变量时,实际上是传递引用(内存地址)而不是整个对象的副本。 继承和多态性:

结构不能继承: 结构不能继承其他结构或类,也不能作为其他结构或类的基类。 类支持继承: 类支持继承和多态性,可以通过派生新类来扩展现有类的功能。 默认构造函数:

结构不能有无参数的构造函数: 结构不能包含无参数的构造函数。每个结构都必须有至少一个有参数的构造函数。 类可以有无参数的构造函数: 类可以包含无参数的构造函数,如果没有提供构造函数,系统会提供默认的无参数构造函数。 赋值行为:

类型为类的变量在赋值时存储的是引用,因此两个变量指向同一个对象。 结构变量在赋值时会复制整个结构,因此每个变量都有自己的独立副本。 传递方式:

类型为类的对象在方法调用时通过引用传递,这意味着在方法中对对象所做的更改会影响到原始对象。 结构对象通常通过值传递,这意味着传递的是结构的副本,而不是原始结构对象本身。因此,在方法中对结构所做的更改不会影响到原始对象。 可空性:

结构体是值类型,不能直接设置为 null:因为 null 是引用类型的默认值,而不是值类型的默认值。如果你需要表示结构体变量的缺失或无效状态,可以使用 Nullable 或称为 T? 的可空类型。 类默认可为null: 类的实例默认可以为 null,因为它们是引用类型。 性能和内存分配:

结构通常更轻量: 由于结构是值类型且在栈上分配内存,它们通常比类更轻量,适用于简单的数据表示。 类可能有更多开销: 由于类是引用类型,可能涉及更多的内存开销和管理。 以下实例中,MyStruct 是一个结构,而 MyClass 是一个类。

注释部分演示了结构不能包含无参数的构造函数、不能继承以及结构的实例复制是复制整个结构的内容。与之相反,类可以包含无参数的构造函数,可以继承,并且实例复制是复制引用。

实例 using System;

// 结构声明 struct MyStruct { public int X; public int Y;

// 结构不能有无参数的构造函数
// public MyStruct()
// {
// }

// 有参数的构造函数
public MyStruct(int x, int y)
{
    X = x;
    Y = y;
}

// 结构不能继承
// struct MyDerivedStruct : MyBaseStruct
// {
// }

}

// 类声明 class MyClass { public int X; public int Y;

// 类可以有无参数的构造函数
public MyClass()
{
}

// 有参数的构造函数
public MyClass(int x, int y)
{
    X = x;
    Y = y;
}

// 类支持继承
// class MyDerivedClass : MyBaseClass
// {
// }

}

class Program { static void Main() { // 结构是值类型,分配在栈上 MyStruct structInstance1 = new MyStruct(1, 2); MyStruct structInstance2 = structInstance1; // 复制整个结构

    // 类是引用类型,分配在堆上
    MyClass classInstance1 = new MyClass(3, 4);
    MyClass classInstance2 = classInstance1; // 复制引用,指向同一个对象

    // 修改结构实例不影响其他实例
    structInstance1.X = 5;
    Console.WriteLine($"Struct: {structInstance1.X}, {structInstance2.X}");

    // 修改类实例会影响其他实例
    classInstance1.X = 6;
    Console.WriteLine($"Class: {classInstance1.X}, {classInstance2.X}");
}

} 针对上述讨论,让我们重写前面的实例:

实例 using System; using System.Text;

struct Books { private string title; private string author; private string subject; private int book_id; public void setValues(string t, string a, string s, int id) { title = t; author = a; subject = s; book_id =id; } public void display() { Console.WriteLine(“Title : {0}”, title); Console.WriteLine(“Author : {0}”, author); Console.WriteLine(“Subject : {0}”, subject); Console.WriteLine(“Book_id :{0}”, book_id); }

};

public class testStructure { public static void Main(string[] args) {

  Books Book1 = new Books(); /* 声明 Book1,类型为 Books */
  Books Book2 = new Books(); /* 声明 Book2,类型为 Books */

  /* book 1 详述 */
  Book1.setValues("C Programming",
  "Nuha Ali", "C Programming Tutorial",6495407);

  /* book 2 详述 */
  Book2.setValues("Telecom Billing",
  "Zara Ali", "Telecom Billing Tutorial", 6495700);

  /* 打印 Book1 信息 */
  Book1.display();

  /* 打印 Book2 信息 */
  Book2.display();

  Console.ReadKey();

} } 当上面的代码被编译和执行时,它会产生下列结果:

Title : C Programming Author : Nuha Ali Subject : C Programming Tutorial Book_id : 6495407 Title : Telecom Billing Author : Zara Ali Subject : Telecom Billing Tutorial Book_id : 6495700

第 章 类

C# 类(Class) 当你定义一个类时,你定义了一个数据类型的蓝图。这实际上并没有定义任何的数据,但它定义了类的名称意味着什么,也就是说,类的对象由什么组成及在这个对象上可执行什么操作。对象是类的实例。构成类的方法和变量称为类的成员。

类的定义 类的定义是以关键字 class 开始,后跟类的名称。类的主体,包含在一对花括号内。下面是类定义的一般形式:

<access specifier> class  class_name
{
    // member variables
    <access specifier> <data type> variable1;
    <access specifier> <data type> variable2;
    ...
    <access specifier> <data type> variableN;
    // member methods
    <access specifier> <return type> method1(parameter_list)
    {
        // method body
    }
    <access specifier> <return type> method2(parameter_list)
    {
        // method body
    }
    ...
    <access specifier> <return type> methodN(parameter_list)
    {
        // method body
    }
}

请注意:

访问标识符 指定了对类及其成员的访问规则。如果没有指定,则使用默认的访问标识符。类的默认访问标识符是 internal,成员的默认访问标识符是 private。 数据类型 指定了变量的类型,返回类型 指定了返回的方法返回的数据类型。 如果要访问类的成员,你要使用点(.)运算符。 点运算符链接了对象的名称和成员的名称。 下面的实例说明了目前为止所讨论的概念:

实例

using System;
namespace BoxApplication
{
    class Box
    {
       public double length;   // 长度
       public double breadth;  // 宽度
       public double height;   // 高度
    }
    class Boxtester
    {
        static void Main(string[] args)
        {
            Box Box1 = new Box();        // 声明 Box1,类型为 Box
            Box Box2 = new Box();        // 声明 Box2,类型为 Box
            double volume = 0.0;         // 体积

            // Box1 详述
            Box1.height = 5.0;
            Box1.length = 6.0;
            Box1.breadth = 7.0;

            // Box2 详述
            Box2.height = 10.0;
            Box2.length = 12.0;
            Box2.breadth = 13.0;
           
            // Box1 的体积
            volume = Box1.height * Box1.length * Box1.breadth;
            Console.WriteLine("Box1 的体积: {0}",  volume);

            // Box2 的体积
            volume = Box2.height * Box2.length * Box2.breadth;
            Console.WriteLine("Box2 的体积: {0}", volume);
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

Box1 的体积: 210 Box2 的体积: 1560 成员函数和封装 类的成员函数是一个在类定义中有它的定义或原型的函数,就像其他变量一样。作为类的一个成员,它能在类的任何对象上操作,且能访问该对象的类的所有成员。

成员变量是对象的属性(从设计角度),且它们保持私有来实现封装。这些变量只能使用公共成员函数来访问。

让我们使用上面的概念来设置和获取一个类中不同的类成员的值:

实例

using System;
namespace BoxApplication
{
    class Box
    {
       private double length;   // 长度
       private double breadth;  // 宽度
       private double height;   // 高度
       public void setLength( double len )
       {
            length = len;
       }

       public void setBreadth( double bre )
       {
            breadth = bre;
       }

       public void setHeight( double hei )
       {
            height = hei;
       }
       public double getVolume()
       {
           return length * breadth * height;
       }
    }
    class Boxtester
    {
        static void Main(string[] args)
        {
            Box Box1 = new Box();        // 声明 Box1,类型为 Box
            Box Box2 = new Box();        // 声明 Box2,类型为 Box
            double volume;               // 体积


            // Box1 详述
            Box1.setLength(6.0);
            Box1.setBreadth(7.0);
            Box1.setHeight(5.0);

            // Box2 详述
            Box2.setLength(12.0);
            Box2.setBreadth(13.0);
            Box2.setHeight(10.0);
       
            // Box1 的体积
            volume = Box1.getVolume();
            Console.WriteLine("Box1 的体积: {0}" ,volume);

            // Box2 的体积
            volume = Box2.getVolume();
            Console.WriteLine("Box2 的体积: {0}", volume);
           
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

Box1 的体积: 210 Box2 的体积: 1560 C# 中的构造函数 类的 构造函数 是类的一个特殊的成员函数,当创建类的新对象时执行。

构造函数的名称与类的名称完全相同,它没有任何返回类型。

下面的实例说明了构造函数的概念:

实例

using System;
namespace LineApplication
{
   class Line
   {
      private double length;   // 线条的长度
      public Line()
      {
         Console.WriteLine("对象已创建");
      }

      public void setLength( double len )
      {
         length = len;
      }
      public double getLength()
      {
         return length;
      }

      static void Main(string[] args)
      {
         Line line = new Line();    
         // 设置线条长度
         line.setLength(6.0);
         Console.WriteLine("线条的长度: {0}", line.getLength());
         Console.ReadKey();
      }
   }
}

当上面的代码被编译和执行时,它会产生下列结果:

对象已创建 线条的长度: 6 默认的构造函数没有任何参数。但是如果你需要一个带有参数的构造函数可以有参数,这种构造函数叫做参数化构造函数。这种技术可以帮助你在创建对象的同时给对象赋初始值,具体请看下面实例:

实例


using System;
namespace LineApplication
{
   class Line
   {
      private double length;   // 线条的长度
      public Line(double len)  // 参数化构造函数
      {
         Console.WriteLine("对象已创建,length = {0}", len);
         length = len;
      }

      public void setLength( double len )
      {
         length = len;
      }
      public double getLength()
      {
         return length;
      }

      static void Main(string[] args)
      {
         Line line = new Line(10.0);
         Console.WriteLine("线条的长度: {0}", line.getLength());
         // 设置线条长度
         line.setLength(6.0);
         Console.WriteLine("线条的长度: {0}", line.getLength());
         Console.ReadKey();
      }
   }
}

当上面的代码被编译和执行时,它会产生下列结果:

对象已创建,length = 10 线条的长度: 10 线条的长度: 6 C# 中的析构函数 类的 析构函数 是类的一个特殊的成员函数,当类的对象超出范围时执行。

析构函数的名称是在类的名称前加上一个波浪形(~)作为前缀,它不返回值,也不带任何参数。

析构函数用于在结束程序(比如关闭文件、释放内存等)之前释放资源。析构函数不能继承或重载。

下面的实例说明了析构函数的概念:

实例

using System; namespace LineApplication { class Line { private double length; // 线条的长度 public Line() // 构造函数 { Console.WriteLine(“对象已创建”); } ~Line() //析构函数 { Console.WriteLine(“对象已删除”); }

  public void setLength( double len )
  {
     length = len;
  }
  public double getLength()
  {
     return length;
  }

  static void Main(string[] args)
  {
     Line line = new Line();
     // 设置线条长度
     line.setLength(6.0);
     Console.WriteLine("线条的长度: {0}", line.getLength());          
  }

} } 当上面的代码被编译和执行时,它会产生下列结果:

对象已创建 线条的长度: 6 对象已删除 C# 类的静态成员 我们可以使用 static 关键字把类成员定义为静态的。当我们声明一个类成员为静态时,意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。

关键字 static 意味着类中只有一个该成员的实例。静态变量用于定义常量,因为它们的值可以通过直接调用类而不需要创建类的实例来获取。静态变量可在成员函数或类的定义外部进行初始化。你也可以在类的定义内部初始化静态变量。

下面的实例演示了静态变量的用法:

实例 using System; namespace StaticVarApplication { class StaticVar { public static int num; public void count() { num++; } public int getNum() { return num; } } class StaticTester { static void Main(string[] args) { StaticVar s1 = new StaticVar(); StaticVar s2 = new StaticVar(); s1.count(); s1.count(); s1.count(); s2.count(); s2.count(); s2.count();
Console.WriteLine(“s1 的变量 num: {0}”, s1.getNum()); Console.WriteLine(“s2 的变量 num: {0}”, s2.getNum()); Console.ReadKey(); } } } 当上面的代码被编译和执行时,它会产生下列结果:

s1 的变量 num: 6 s2 的变量 num: 6 你也可以把一个成员函数声明为 static。这样的函数只能访问静态变量。静态函数在对象被创建之前就已经存在。下面的实例演示了静态函数的用法:

实例

using System;
namespace StaticVarApplication
{
    class StaticVar
    {
       public static int num;
        public void count()
        {
            num++;
        }
        public static int getNum()
        {
            return num;
        }
    }
    class StaticTester
    {
        static void Main(string[] args)
        {
            StaticVar s = new StaticVar();
            s.count();
            s.count();
            s.count();                  
            Console.WriteLine("变量 num: {0}", StaticVar.getNum());
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

变量 num: 3

文件的输入与输出

一个 文件 是一个存储在磁盘中带有指定名称和目录路径的数据集合。当打开文件进行读写时,它变成一个 流。

从根本上说,流是通过通信路径传递的字节序列。有两个主要的流:输入流 和 输出流。输入流用于从文件读取数据(读操作),输出流用于向文件写入数据(写操作)。

C# I/O 类

System.IO 命名空间有各种不同的类,用于执行各种文件操作,如创建和删除文件、读取或写入文件,关闭文件等。

下表列出了一些 System.IO 命名空间中常用的非抽象类:

I/O 类 描述 BinaryReader 从二进制流读取原始数据。 BinaryWriter 以二进制格式写入原始数据。 BufferedStream 字节流的临时存储。 Directory 有助于操作目录结构。 DirectoryInfo 用于对目录执行操作。 DriveInfo 提供驱动器的信息。 File 有助于处理文件。 FileInfo 用于对文件执行操作。 FileStream 用于文件中任何位置的读写。 MemoryStream 用于随机访问存储在内存中的数据流。 Path 对路径信息执行操作。 StreamReader 用于从字节流中读取字符。 StreamWriter 用于向一个流中写入字符。 StringReader 用于读取字符串缓冲区。 StringWriter 用于写入字符串缓冲区。 FileStream 类 System.IO 命名空间中的 FileStream 类有助于文件的读写与关闭。该类派生自抽象类 Stream。

您需要创建一个 FileStream 对象来创建一个新的文件,或打开一个已有的文件。创建 FileStream 对象的语法如下:

FileStream <object_name> = new FileStream( <file_name>, , , ); 例如,创建一个 FileStream 对象 F 来读取名为 sample.txt 的文件:

FileStream F = new FileStream(“sample.txt”, FileMode.Open, FileAccess.Read, FileShare.Read); 参数 描述 FileMode FileMode 枚举定义了各种打开文件的方法。FileMode 枚举的成员有:

Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件。 Create:创建一个新的文件。如果文件已存在,则删除旧文件,然后创建新文件。 CreateNew:指定操作系统应创建一个新的文件。如果文件已存在,则抛出异常。 Open:打开一个已有的文件。如果文件不存在,则抛出异常。 OpenOrCreate:指定操作系统应打开一个已有的文件。如果文件不存在,则用指定的名称创建一个新的文件打开。 Truncate:打开一个已有的文件,文件一旦打开,就将被截断为零字节大小。然后我们可以向文件写入全新的数据,但是保留文件的初始创建日期。如果文件不存在,则抛出异常。 FileAccess FileAccess 枚举的成员有:Read、ReadWrite 和 Write。

FileShare FileShare 枚举的成员有:

Inheritable:允许文件句柄可由子进程继承。Win32 不直接支持此功能。 None:谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。 Read:允许随后打开文件读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。 ReadWrite:允许随后打开文件读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。 Write:允许随后打开文件写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。 Delete:允许随后删除文件。 实例 下面的程序演示了 FileStream 类的用法:

实例 using System; using System.IO;

namespace FileIOApplication { class Program { static void Main(string[] args) { FileStream F = new FileStream(“test.dat”, FileMode.OpenOrCreate, FileAccess.ReadWrite);

        for (int i = 1; i <= 20; i++)
        {
            F.WriteByte((byte)i);
        }

        F.Position = 0;

        for (int i = 0; i <= 20; i++)
        {
            Console.Write(F.ReadByte() + " ");
        }
        F.Close();
        Console.ReadKey();
    }
}

} 当上面的代码被编译和执行时,它会产生下列结果:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1 C# 高级文件操作 上面的实例演示了 C# 中简单的文件操作。但是,要充分利用 C# System.IO 类的强大功能,您需要知道这些类常用的属性和方法。

在下面的章节中,我们将讨论这些类和它们执行的操作。请单击链接详细了解各个部分的知识:

主题 描述 文本文件的读写 它涉及到文本文件的读写。StreamReader 和 StreamWriter 类有助于完成文本文件的读写。 二进制文件的读写 它涉及到二进制文件的读写。BinaryReader 和 BinaryWriter 类有助于完成二进制文件的读写。

测绘程序设计

读取数据

  • 利用StreamReader读取txt数据
using System.IO;

namespace readFile
{
    class Program
    {
        static void Main(string[] args)
        {   
            ReadData();
            Console.ReadKey();
        }
        static void ReadData() 
        {
            string filename;//= @"D:\study\ConsoleApp3\data.txt";
            Console.WriteLine("please input file name:");
            filename = Convert.ToString(Console.ReadLine());
            StreamReader reader = new StreamReader(filename);
            string buf = reader.ReadLine();
            int[] number = new int[4];
            string[] siteName =new string[4];
            double[] B = new double[4];
            double[] L = new double[4];

            for (int i = 0; i < 2; i++) //i为数据的行数
            {
                buf = reader.ReadLine();
                var arr = buf.Split(' ');
                number[i] = Convert.ToInt32(arr[0]);
                siteName[i] = arr[1];
                B[i] = Convert.ToDouble(arr[2]);
                L[i] = Convert.ToDouble(arr[3]);
                Console.WriteLine("{0},{1}",B[i], L[i]);
            }
            reader.Close();
        }
 
    }
}

大地线计算