本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:C#通讯录管理系统是一个基于C#和Windows Forms开发的桌面应用,具备联系人添加、搜索、编辑等核心功能。系统结合了面向对象编程、数据库操作、事件驱动机制及用户界面设计等关键技术,适用于学习C#高级开发和桌面应用构建。通过该项目,开发者可掌握数据结构应用、异常处理、代码组织、调试测试等实用技能,是从理论到实践的完整编程训练项目。

1. C#语言基础与面向对象编程

本章主要介绍C#语言的基本语法、数据类型、运算符、控制结构等基础内容,并深入讲解面向对象编程的核心概念,包括类与对象、封装、继承与多态等,为后续开发通讯录管理系统打下坚实的编程基础。

1.1 C#语言概述

C# 是一种现代、面向对象、类型安全的编程语言,专为 .NET 平台设计。它融合了 C++ 的强大功能与 Java 的易用性,并结合了现代软件开发的最佳实践。使用 C# 可以开发多种类型的应用程序,包括控制台应用、Windows Forms、Web 应用(ASP.NET)、服务程序、移动应用(Xamarin)等。

C# 代码运行在 .NET 公共语言运行时(CLR)之上,具有自动内存管理、垃圾回收、异常处理等高级功能。开发者无需手动管理内存,可以专注于业务逻辑实现。以下是一个最简单的 C# 控制台应用程序示例:

using System;

namespace HelloWorldApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!"); // 输出文本到控制台
        }
    }
}

代码说明:

  • using System; :引入 System 命名空间,包含基本类如 Console
  • namespace :命名空间用于组织代码结构。
  • class Program :C# 是纯面向对象的语言,所有代码必须包含在类中。
  • static void Main(string[] args) :程序的入口点,程序从这里开始执行。
  • Console.WriteLine(...) :将字符串输出到控制台窗口。

该程序结构清晰地展示了 C# 程序的基本骨架。在本章后续内容中,我们将深入讲解变量、数据类型、运算符、控制语句以及面向对象编程的核心概念,帮助你构建稳固的编程基础。

2. Windows Forms图形界面开发

Windows Forms 是 .NET 框架中用于构建桌面应用程序的核心界面开发技术之一。它提供了丰富的控件库和事件驱动机制,使得开发者能够快速构建功能完善、界面友好的桌面应用。本章将从 Windows Forms 的基本结构入手,逐步深入讲解控件使用、界面布局、多窗体交互以及样式设计等关键技术点,为后续开发通讯录管理系统提供扎实的界面基础。

2.1 Windows Forms概述

Windows Forms(简称 WinForms)是 Microsoft 提供的一种基于事件驱动的图形用户界面(GUI)框架,广泛应用于 Windows 桌面应用程序开发。它以 System.Windows.Forms 命名空间为核心,通过丰富的控件、布局管理器和事件处理机制,为开发者提供了一个高效的开发平台。

2.1.1 理解Windows Forms应用程序结构

一个典型的 Windows Forms 应用程序由多个核心组件构成,包括:

  • 主窗体(Form) :应用程序的主界面,继承自 System.Windows.Forms.Form 类。
  • 控件(Control) :用于构建用户界面的元素,如按钮(Button)、文本框(TextBox)、标签(Label)等。
  • 事件处理(Event Handling) :通过事件模型实现用户交互,例如按钮点击、窗体加载等。
  • 程序入口(Program.cs) :定义应用程序的启动点,通常包含 Application.Run() 方法。
  • 资源文件(Resource Files) :用于管理图标、图片、字符串等本地化资源。

下面是一个最简单的 Windows Forms 应用程序结构示例:

using System;
using System.Windows.Forms;

namespace SimpleWinFormsApp
{
    public class MainForm : Form
    {
        private Button button;

        public MainForm()
        {
            InitializeComponents();
        }

        private void InitializeComponents()
        {
            this.Text = "我的第一个WinForms程序";
            this.Width = 400;
            this.Height = 300;

            button = new Button();
            button.Text = "点击我";
            button.Location = new System.Drawing.Point(150, 100);
            button.Click += new EventHandler(Button_Click);

            this.Controls.Add(button);
        }

        private void Button_Click(object sender, EventArgs e)
        {
            MessageBox.Show("你点击了按钮!");
        }

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

逐行代码解读与逻辑分析:

  1. using System; using System.Windows.Forms; 引入必要的命名空间。
  2. 定义 MainForm 类,继承自 Form ,表示主窗体。
  3. 构造函数中调用 InitializeComponents() 方法进行界面初始化。
  4. InitializeComponents() 方法中设置窗体标题、大小,创建按钮控件,并设置其位置和点击事件。
  5. Button_Click 方法作为按钮点击事件的响应函数,弹出一个消息框。
  6. Main() 方法为程序入口,启用视觉样式并运行主窗体。

参数说明:

  • Application.Run(new MainForm()) :启动应用程序,并将主窗体显示出来。
  • button.Location :设置控件在窗体中的位置,单位为像素。
  • Click += new EventHandler(Button_Click) :绑定点击事件处理函数。

2.1.2 创建第一个Windows Forms项目

在实际开发中,通常使用 Visual Studio 来创建 Windows Forms 项目,这样可以借助其强大的设计器工具快速构建界面。以下是使用 Visual Studio 创建第一个 Windows Forms 项目的步骤:

步骤一:启动 Visual Studio
  1. 打开 Visual Studio。
  2. 点击“创建新项目”。
步骤二:选择模板
  1. 在“创建新项目”窗口中,选择“Windows Forms 应用程序(.NET Framework)”或“Windows Forms 应用程序(.NET)”。
  2. 输入项目名称,例如 MyFirstWinFormsApp
  3. 设置项目保存路径,点击“创建”。
步骤三:熟悉项目结构

Visual Studio 会自动创建以下文件结构:

  • Program.cs :程序入口。
  • Form1.cs :主窗体类文件。
  • Form1.Designer.cs :设计器生成的代码,不建议手动修改。
  • Properties :资源文件和程序集信息。
步骤四:添加控件并绑定事件
  1. 打开 Form1.cs 的设计视图。
  2. 从工具箱中拖动控件(如 Button、TextBox、Label)到窗体上。
  3. 双击控件自动生成事件处理函数(如 Button 的 Click 事件)。

示例:添加一个按钮并实现点击事件

private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("欢迎使用Windows Forms!");
}

逻辑分析:

  • button1_Click 是双击按钮后自动生成的事件处理函数。
  • 调用 MessageBox.Show() 显示一个弹窗提示。
步骤五:运行程序

点击工具栏上的“启动”按钮或按 F5 运行程序,窗体将显示在屏幕上,点击按钮即可看到提示信息。

2.2 控件与界面布局

在 Windows Forms 中,控件是构建用户界面的基本单元。掌握常用控件的使用方法和布局技巧,是开发高效、美观界面的关键。

2.2.1 常用控件的使用与属性设置

WinForms 提供了大量控件,常见的包括:

控件名称 用途说明 常用属性
Button 触发操作的按钮 Text, Click, Enabled
TextBox 输入文本框 Text, ReadOnly, MaxLength
Label 显示静态文本 Text, AutoSize
CheckBox 多选框 Checked, Text
RadioButton 单选按钮 Checked, GroupName
ListBox 显示多个选项的列表 Items, SelectedIndex
ComboBox 下拉列表选择器 Items, SelectedItem
DataGridView 显示表格数据 DataSource, Columns
示例:使用 TextBox 和 Button 实现简单输入输出
private void button1_Click(object sender, EventArgs e)
{
    string input = textBox1.Text;
    if (!string.IsNullOrEmpty(input))
    {
        label1.Text = "你输入的是:" + input;
    }
    else
    {
        label1.Text = "请输入内容!";
    }
}

逻辑分析:

  • textBox1.Text 获取用户输入。
  • 判断输入是否为空,更新 label1.Text 显示结果。

参数说明:

  • textBox1.Text :获取或设置文本框中的内容。
  • label1.Text :设置标签显示的文本内容。
  • string.IsNullOrEmpty() :用于判断字符串是否为空或 null。

2.2.2 使用布局控件实现自适应界面

为了使界面在不同分辨率或窗口大小下保持良好的显示效果,WinForms 提供了多种布局控件,如:

  • FlowLayoutPanel :自动按行或列排列子控件。
  • TableLayoutPanel :以表格形式布局控件。
  • SplitContainer :分割窗体区域,支持动态调整。
示例:使用 TableLayoutPanel 布局控件
TableLayoutPanel panel = new TableLayoutPanel();
panel.ColumnCount = 2;
panel.RowCount = 2;
panel.Dock = DockStyle.Fill;

panel.Controls.Add(new Label() { Text = "用户名:" }, 0, 0);
panel.Controls.Add(new TextBox(), 1, 0);
panel.Controls.Add(new Label() { Text = "密码:" }, 0, 1);
panel.Controls.Add(new TextBox() { PasswordChar = '*' }, 1, 1);

this.Controls.Add(panel);

逻辑分析:

  • 创建一个 2x2 的表格布局控件。
  • 添加用户名和密码输入项,分别放置在表格的不同单元格中。
  • 设置密码框的 PasswordChar 属性为 * ,实现密码隐藏。

参数说明:

  • ColumnCount RowCount :定义表格的行列数。
  • Dock = DockStyle.Fill :使布局控件填满父容器。
  • PasswordChar :设置密码框中显示的字符。
流程图:TableLayoutPanel 布局结构
graph TD
    A[TableLayoutPanel] --> B[第1行第1列: 用户名标签]
    A --> C[第1行第2列: 文本框]
    A --> D[第2行第1列: 密码标签]
    A --> E[第2行第2列: 密码框]

通过上述方式,开发者可以构建出结构清晰、适应性强的界面布局,为后续功能开发打下良好基础。

3. 事件驱动编程模型与交互设计

在现代图形用户界面(GUI)开发中, 事件驱动编程模型 是构建用户交互逻辑的核心机制。C#语言与Windows Forms结合,为我们提供了一套完善的事件与委托体系,使得开发者可以高效地处理用户操作、界面响应与业务逻辑的交互。本章将深入探讨事件与委托机制的底层原理,分析用户交互设计中的关键流程,并讨论如何通过MVP等设计模式实现界面与逻辑的分离。

3.1 事件与委托机制

事件驱动编程模型的核心是 委托(Delegate)和事件(Event) ,它们构成了C#中异步、响应式编程的基础。

3.1.1 理解事件和委托的基本原理

委托(Delegate) 是一种类型安全的函数指针,它允许将方法作为参数传递,并在运行时动态调用。而 事件(Event) 是基于委托的封装,用于在对象之间建立发布-订阅机制。

我们可以将委托看作是“方法的类型”,而事件则是对委托的包装,限制外部直接调用,只能通过 += 和 -= 操作符进行注册或注销。

示例代码:定义一个委托与事件
public delegate void NotifyEventHandler(string message);

public class EventPublisher
{
    public event NotifyEventHandler Notify;

    public void RaiseEvent(string message)
    {
        Notify?.Invoke(message);
    }
}

public class EventSubscriber
{
    public void OnNotify(string message)
    {
        Console.WriteLine($"收到消息:{message}");
    }
}
逻辑分析:
  • NotifyEventHandler 是一个委托类型,定义了一个方法签名,接受一个字符串参数,无返回值。
  • EventPublisher 类中定义了一个 event ,其类型为 NotifyEventHandler ,表示当事件触发时,会调用所有注册的方法。
  • RaiseEvent 方法用于触发事件,使用 ?.Invoke 避免空引用异常。
  • EventSubscriber 是事件的订阅者,其中 OnNotify 方法符合委托签名,可以注册到事件中。
参数说明:
  • message :事件传递的参数,用于携带通知信息。
执行流程图(Mermaid):
sequenceDiagram
    participant Publisher
    participant Subscriber

    Publisher->>Subscriber: 注册OnNotify到Notify事件
    Publisher->>Publisher: 调用RaiseEvent("Hello")
    Publisher->>Subscriber: 调用OnNotify("Hello")
    Subscriber-->>Console: 输出消息

通过这个机制,我们可以构建出响应用户操作、界面变化、数据更新等行为的逻辑体系。

3.1.2 自定义事件处理逻辑

在实际开发中,事件处理通常与用户交互紧密相关。我们可以通过自定义事件,将界面控件与业务逻辑进行解耦。

示例:自定义联系人添加事件
public class ContactEventArgs : EventArgs
{
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
}

public class ContactManager
{
    public event EventHandler<ContactEventArgs> ContactAdded;

    public void AddContact(string name, string phone)
    {
        // 模拟添加联系人逻辑
        Console.WriteLine($"添加联系人:{name} - {phone}");

        // 触发事件
        OnContactAdded(new ContactEventArgs { Name = name, PhoneNumber = phone });
    }

    protected virtual void OnContactAdded(ContactEventArgs e)
    {
        ContactAdded?.Invoke(this, e);
    }
}
逻辑分析:
  • ContactEventArgs 是自定义的事件参数类,继承自 EventArgs ,用于携带联系人信息。
  • ContactManager 提供了 AddContact 方法用于添加联系人,并触发 ContactAdded 事件。
  • OnContactAdded 是一个保护方法,用于封装事件触发逻辑,便于子类重写。
参数说明:
  • name :联系人姓名
  • phone :联系电话
使用示例:
ContactManager manager = new ContactManager();
manager.ContactAdded += (sender, e) =>
{
    Console.WriteLine($"事件触发 - 新增联系人:{e.Name} - {e.PhoneNumber}");
};

manager.AddContact("张三", "13800001111");

输出结果:

添加联系人:张三 - 13800001111
事件触发 - 新增联系人:张三 - 13800001111

通过这种方式,我们可以将联系人添加的业务逻辑与事件响应进行分离,提高代码的可维护性与扩展性。

3.2 用户交互设计

用户交互设计是构建友好、高效应用程序的关键环节。本节将重点介绍按钮点击与数据响应流程,以及输入验证与提示机制的设计。

3.2.1 按钮点击与数据响应流程

在Windows Forms中,用户操作(如按钮点击)通常会触发事件,从而驱动界面与数据的交互。

示例:按钮点击事件绑定
private void btnAddContact_Click(object sender, EventArgs e)
{
    string name = txtName.Text;
    string phone = txtPhone.Text;

    if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(phone))
    {
        MessageBox.Show("姓名和电话不能为空!");
        return;
    }

    contactManager.AddContact(name, phone);
}
逻辑分析:
  • btnAddContact_Click 是按钮的点击事件处理器。
  • 获取输入框中的内容,并进行空值判断。
  • 如果输入为空,弹出提示框。
  • 否则,调用 contactManager.AddContact 方法,添加联系人。
参数说明:
  • txtName txtPhone 是界面控件,用于获取用户输入。
  • contactManager 是一个 ContactManager 实例,负责处理联系人添加逻辑。
表格:按钮点击流程分析
步骤 操作内容 触发事件
1 用户点击“添加”按钮 btnAddContact_Click
2 获取输入值 控件 .Text 属性
3 输入验证 条件判断
4 添加联系人 contactManager.AddContact
5 触发 ContactAdded 事件 通知其他模块

3.2.2 输入验证与提示机制设计

输入验证是用户交互中的重要环节,确保数据的合法性与完整性。

示例:输入验证与提示
private bool ValidateInput(string name, string phone)
{
    if (string.IsNullOrEmpty(name))
    {
        errorProvider.SetError(txtName, "姓名不能为空");
        return false;
    }
    else
    {
        errorProvider.SetError(txtName, "");
    }

    if (string.IsNullOrEmpty(phone))
    {
        errorProvider.SetError(txtPhone, "电话不能为空");
        return false;
    }
    else
    {
        errorProvider.SetError(txtPhone, "");
    }

    return true;
}
逻辑分析:
  • 使用 ErrorProvider 控件在界面上显示错误提示。
  • 分别对姓名和电话字段进行空值检查。
  • 若为空,设置错误信息并返回 false ;否则清除错误并返回 true
参数说明:
  • errorProvider :Windows Forms 控件,用于在控件旁边显示错误图标和提示信息。
  • txtName , txtPhone :文本框控件,分别对应姓名和电话输入。
验证流程图(Mermaid):
graph TD
    A[开始验证] --> B{姓名是否为空?}
    B -->|是| C[显示错误提示]
    B -->|否| D{电话是否为空?}
    D -->|是| E[显示错误提示]
    D -->|否| F[验证通过]

通过这种验证机制,可以有效提升用户体验,避免无效数据的提交。

3.3 界面与逻辑分离策略

在复杂的应用中,保持界面与业务逻辑的分离是软件工程中的最佳实践。本节将介绍如何使用MVP模式进行界面解耦,并探讨事件与业务逻辑的协作机制。

3.3.1 实现MVP模式进行界面解耦

MVP(Model-View-Presenter) 是一种常用于解耦界面与逻辑的设计模式,特别适用于Windows Forms等UI框架。

示例:MVP模式结构设计
// View 接口
public interface IContactView
{
    string Name { get; }
    string Phone { get; }
    void ShowMessage(string message);
}

// Presenter
public class ContactPresenter
{
    private IContactView _view;
    private ContactManager _manager;

    public ContactPresenter(IContactView view)
    {
        _view = view;
        _manager = new ContactManager();
        _manager.ContactAdded += OnContactAdded;
    }

    public void AddContact()
    {
        if (!string.IsNullOrEmpty(_view.Name) && !string.IsNullOrEmpty(_view.Phone))
        {
            _manager.AddContact(_view.Name, _view.Phone);
        }
        else
        {
            _view.ShowMessage("姓名和电话不能为空!");
        }
    }

    private void OnContactAdded(object sender, ContactEventArgs e)
    {
        _view.ShowMessage($"联系人 {e.Name} 已添加");
    }
}
逻辑分析:
  • IContactView 是界面的抽象接口,定义了获取输入与显示消息的方法。
  • ContactPresenter 是Presenter类,负责协调View与Model之间的交互。
  • ContactManager 作为Model层,处理联系人添加逻辑。
  • 通过事件 ContactAdded ,Presenter可以在联系人添加后通知View显示消息。
参数说明:
  • _view :实现 IContactView 接口的具体界面类。
  • _manager :联系人管理类,负责数据操作。
在Windows Forms中使用:
public partial class MainForm : Form, IContactView
{
    private ContactPresenter _presenter;

    public string Name => txtName.Text;
    public string Phone => txtPhone.Text;

    public MainForm()
    {
        InitializeComponent();
        _presenter = new ContactPresenter(this);
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        _presenter.AddContact();
    }

    public void ShowMessage(string message)
    {
        MessageBox.Show(message);
    }
}

通过MVP模式,我们可以实现界面与逻辑的完全分离,便于单元测试和后期维护。

3.3.2 事件与业务逻辑的协作机制

事件机制在MVP模式中也扮演着重要角色,尤其在View与Presenter之间的通信中。

示例:事件驱动的MVP协作
// 在Presenter中注册事件
_manager.ContactAdded += OnContactAdded;

private void OnContactAdded(object sender, ContactEventArgs e)
{
    _view.ShowMessage($"联系人 {e.Name} 已添加");
}
逻辑分析:
  • 当联系人被添加时, ContactAdded 事件被触发。
  • OnContactAdded 方法被调用,向View发送消息。
  • View通过 ShowMessage 显示提示信息。
协作流程图(Mermaid):
sequenceDiagram
    participant View
    participant Presenter
    participant Model

    View->>Presenter: 点击添加按钮
    Presenter->>Model: 调用AddContact
    Model->>Presenter: 触发ContactAdded事件
    Presenter->>View: 调用ShowMessage
    View-->>User: 显示提示信息

这种协作机制使得界面与逻辑之间通过事件进行通信,实现松耦合的设计。

通过本章内容,我们深入剖析了C#中事件与委托的核心机制,演示了用户交互设计中的关键流程,并探讨了如何通过MVP等设计模式实现界面与逻辑的分离。这些内容将为后续开发通讯录系统提供坚实的基础。

4. 数据库连接与操作(如SQL Server)

在现代应用程序开发中,数据库连接与操作是系统稳定运行和数据持久化的核心环节。本章将围绕SQL Server这一主流关系型数据库系统,系统性地讲解其在C#环境中的连接与操作机制。通过本章内容,读者将掌握从数据库安装配置、C#连接数据库、到数据操作与事务控制的完整流程,为后续开发通讯录系统提供坚实的数据支撑。

4.1 数据库基础与SQL Server简介

4.1.1 关系型数据库基本概念

关系型数据库(Relational Database)是目前应用最广泛的数据库类型之一,其核心概念基于 关系模型 ,由表(Table)、字段(Column)、记录(Row)组成,数据之间通过主键(Primary Key)和外键(Foreign Key)建立关联。

  • 表(Table) :数据存储的基本单位,由行和列构成。
  • 字段(Column) :描述数据的属性,例如姓名、电话等。
  • 记录(Row) :表示一个具体的实体,例如一条联系人信息。
  • 主键(Primary Key) :唯一标识每条记录的字段,不能重复。
  • 外键(Foreign Key) :用于建立表与表之间的关联,确保数据完整性。

SQL(Structured Query Language)是用于操作关系型数据库的标准语言,支持数据定义(DDL)、数据操作(DML)和数据控制(DCL)等功能。

概念 描述
表(Table) 存储数据的基本结构
主键 唯一标识一条记录
外键 建立表间关联
索引 提高查询效率
视图 虚拟表,简化查询逻辑

SQL Server 是由微软开发的关系型数据库管理系统(RDBMS),支持大型企业级应用,具备高可用性、安全性与可扩展性。它广泛用于.NET平台下的数据持久化解决方案中。

4.1.2 SQL Server的安装与配置

SQL Server的安装包括以下几个关键步骤:

安装步骤:
  1. 下载安装包
    访问微软官网,下载 SQL Server Express(免费版本)或标准版本安装程序。

  2. 运行安装向导
    双击安装程序,进入安装中心,选择“新SQL Server独立安装”。

  3. 产品密钥与许可协议
    输入产品密钥(若为付费版本)并接受许可协议。

  4. 功能选择
    勾选需要安装的组件,如数据库引擎、管理工具等。

  5. 实例配置
    选择默认实例或命名实例,建议首次使用默认实例(MSSQLSERVER)。

  6. 服务器配置
    设置服务账户和启动类型,通常使用“NT AUTHORITY\SYSTEM”作为默认账户。

  7. 数据库引擎配置
    设置身份验证模式:
    - Windows身份验证 :适合本地开发环境。
    - 混合模式(SQL Server + Windows) :适合生产环境,需设置sa密码。

  8. 安装完成
    等待安装完成后,重启系统(如提示)。

配置连接:

安装完成后,使用 SQL Server Management Studio(SSMS) 进行连接测试:

-- 连接本地SQL Server实例
Server: (local)
Authentication: Windows Authentication

若连接成功,即可创建数据库并执行建表语句:

-- 创建通讯录数据库
CREATE DATABASE ContactDB;
GO

USE ContactDB;

-- 创建联系人表
CREATE TABLE Contacts (
    ContactID INT PRIMARY KEY IDENTITY(1,1),
    Name NVARCHAR(100) NOT NULL,
    Phone NVARCHAR(20),
    Email NVARCHAR(100),
    Address NVARCHAR(255)
);
参数说明:
  • IDENTITY(1,1) :自动递增主键,从1开始每次增加1。
  • NVARCHAR(n) :存储Unicode字符,n表示最大字符数。
  • NOT NULL :字段不能为空。

通过上述步骤,我们完成了SQL Server的安装与基本配置,为C#项目连接数据库奠定了基础。

4.2 C#与数据库的连接

4.2.1 使用SqlConnection连接数据库

在C#中, SqlConnection 类用于建立与SQL Server数据库的连接。它位于 System.Data.SqlClient 命名空间下,是ADO.NET的核心类之一。

示例代码:
using System;
using System.Data.SqlClient;

class Program
{
    static void Main()
    {
        string connectionString = "Server=(local);Database=ContactDB;Trusted_Connection=True;";

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            try
            {
                connection.Open();
                Console.WriteLine("数据库连接成功!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("连接失败:" + ex.Message);
            }
        }
    }
}
逐行分析:
  • using System.Data.SqlClient; :引入命名空间,包含数据库连接相关类。
  • string connectionString :定义连接字符串,包含服务器地址、数据库名、身份验证方式等信息。
  • SqlConnection connection = new SqlConnection(connectionString) :创建连接对象。
  • connection.Open(); :打开数据库连接。
  • try-catch :捕获连接异常,增强程序健壮性。
连接字符串参数说明:
参数 含义
Server 数据库服务器地址, (local) 表示本地
Database 要连接的数据库名称
Trusted_Connection 是否使用Windows身份验证, True 表示启用

4.2.2 配置连接字符串与安全策略

连接字符串是C#连接数据库的关键配置项,通常存储在配置文件中(如 App.config appsettings.json ),以实现灵活配置和安全控制。

1. 配置文件方式:

App.config 中添加:

<configuration>
  <connectionStrings>
    <add name="ContactDB" 
         connectionString="Server=(local);Database=ContactDB;Trusted_Connection=True;" 
         providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

在代码中读取:

string connectionString = ConfigurationManager.ConnectionStrings["ContactDB"].ConnectionString;
2. 安全策略:
  • 避免硬编码连接字符串 :防止敏感信息泄露。
  • 使用Windows身份验证 :减少密码管理风险。
  • 限制数据库访问权限 :为应用程序账户分配最小权限。
  • 加密连接字符串 :使用 aspnet_regiis 工具加密配置节。
3. 连接池优化:

SQL Server支持连接池(Connection Pooling),提升性能:

string connectionString = "Server=(local);Database=ContactDB;Trusted_Connection=True;Max Pool Size=100;";
参数 含义
Max Pool Size 最大连接数,默认100
Min Pool Size 最小连接数,默认0
Connection Timeout 连接超时时间,默认15秒

通过合理配置连接字符串和安全策略,我们可以在C#项目中安全、高效地连接SQL Server数据库,为后续数据操作打下基础。

4.3 数据操作与事务控制

4.3.1 执行SQL语句与存储过程

在C#中,使用 SqlCommand 类执行SQL语句和存储过程,支持查询、插入、更新和删除操作。

1. 执行简单SQL语句:
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    string query = "INSERT INTO Contacts (Name, Phone, Email) VALUES (@Name, @Phone, @Email)";
    using (SqlCommand command = new SqlCommand(query, connection))
    {
        command.Parameters.AddWithValue("@Name", "张三");
        command.Parameters.AddWithValue("@Phone", "13800138000");
        command.Parameters.AddWithValue("@Email", "zhangsan@example.com");
        int rowsAffected = command.ExecuteNonQuery();
        Console.WriteLine($"{rowsAffected} 行受影响");
    }
}
逻辑分析:
  • SqlCommand :封装SQL语句和连接对象。
  • Parameters.AddWithValue :添加参数防止SQL注入。
  • ExecuteNonQuery :执行非查询操作,返回受影响行数。
2. 调用存储过程:
-- 创建存储过程
CREATE PROCEDURE InsertContact
    @Name NVARCHAR(100),
    @Phone NVARCHAR(20),
    @Email NVARCHAR(100)
AS
BEGIN
    INSERT INTO Contacts (Name, Phone, Email) VALUES (@Name, @Phone, @Email)
END

C#调用:

using (SqlCommand command = new SqlCommand("InsertContact", connection))
{
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.AddWithValue("@Name", "李四");
    command.Parameters.AddWithValue("@Phone", "13900139000");
    command.Parameters.AddWithValue("@Email", "lisi@example.com");

    int rowsAffected = command.ExecuteNonQuery();
    Console.WriteLine($"{rowsAffected} 行受影响");
}
参数说明:
  • CommandType.StoredProcedure :指定命令类型为存储过程。
  • 使用存储过程可以提高执行效率、增强代码可维护性。

4.3.2 使用事务保障数据一致性

在进行多条数据库操作时,事务(Transaction)用于确保数据的一致性和完整性。事务具有ACID特性:

  • 原子性(Atomicity) :全部成功或全部失败。
  • 一致性(Consistency) :数据状态保持一致。
  • 隔离性(Isolation) :事务之间互不干扰。
  • 持久性(Durability) :提交后数据永久保存。
事务操作流程图:
graph TD
    A[开始事务] --> B[执行SQL操作]
    B --> C{操作是否成功}
    C -- 是 --> D[提交事务]
    C -- 否 --> E[回滚事务]
    D --> F[事务结束]
    E --> F
示例代码:
using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    SqlTransaction transaction = connection.BeginTransaction();

    try
    {
        using (SqlCommand command1 = new SqlCommand("INSERT INTO Contacts (Name) VALUES ('王五')", connection, transaction))
        {
            command1.ExecuteNonQuery();
        }

        using (SqlCommand command2 = new SqlCommand("INSERT INTO Contacts (Name) VALUES ('赵六')", connection, transaction))
        {
            command2.ExecuteNonQuery();
        }

        transaction.Commit(); // 提交事务
        Console.WriteLine("事务提交成功");
    }
    catch (Exception ex)
    {
        transaction.Rollback(); // 回滚事务
        Console.WriteLine("事务回滚:" + ex.Message);
    }
}
逻辑分析:
  • BeginTransaction() :开启事务。
  • Commit() :提交事务,所有更改生效。
  • Rollback() :回滚事务,撤销所有更改。
  • 使用 try-catch 确保异常情况下事务回滚。

通过事务控制,我们可以有效避免因程序异常或数据库错误导致的数据不一致问题,为通讯录系统的数据操作提供可靠保障。

5. ADO.NET与ORM框架使用(如Entity Framework)

在现代软件开发中,数据访问层的构建效率和可维护性直接决定了系统的可扩展性和稳定性。传统的ADO.NET虽然提供了对数据库的底层控制能力,但其繁琐的代码结构和易出错的操作方式使得开发效率难以提升。为此,ORM(对象关系映射)框架如Entity Framework应运而生,它通过将数据库表结构映射为C#类,极大地简化了数据访问逻辑。本章将深入讲解ADO.NET的工作机制,并对比其与EF Core在实际开发中的差异与优势。

5.1 ADO.NET基础

5.1.1 数据集与数据适配器的工作机制

ADO.NET是.NET框架中用于访问数据库的核心组件之一,其核心对象包括 Connection Command DataReader DataAdapter DataSet 。其中, DataAdapter DataSet 的组合为开发人员提供了一种离线数据处理的方式。

  • DataAdapter :负责从数据库中检索数据,并填充到 DataSet 中,也可以将 DataSet 中的更改更新回数据库。
  • DataSet :是一个内存中的数据缓存,可以包含多个 DataTable ,每个 DataTable 又包含多个 DataRow DataColumn
流程图:DataSet与DataAdapter的交互机制
graph TD
    A[数据库] --> B[DataAdapter]
    B --> C[DataSet]
    C --> D[DataTable]
    D --> E[DataRow]
    D --> F[DataColumn]
    C --> G[数据绑定控件]

如上图所示, DataAdapter 从数据库获取数据后填充到 DataSet ,然后 DataSet 内的 DataTable 可以被绑定到 UI 控件中进行展示。这种方式的优点是可以在断开数据库连接的状态下操作数据,提升了系统的响应速度和稳定性。

示例代码:使用DataAdapter和DataSet读取联系人信息
using System;
using System.Data;
using System.Data.SqlClient;

class Program
{
    static void Main()
    {
        string connectionString = "Server=.;Database=ContactDB;Trusted_Connection=True;";
        string query = "SELECT * FROM Contacts";

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
            DataSet dataSet = new DataSet();

            // 填充DataSet
            adapter.Fill(dataSet, "Contacts");

            // 获取DataTable
            DataTable contactTable = dataSet.Tables["Contacts"];

            foreach (DataRow row in contactTable.Rows)
            {
                Console.WriteLine($"ID: {row["ID"]}, Name: {row["Name"]}, Phone: {row["Phone"]}");
            }
        }
    }
}
代码逐行解析:
  1. 连接字符串 :定义了连接到SQL Server数据库的参数,包括服务器地址、数据库名称和认证方式。
  2. SQL查询语句 :用于从 Contacts 表中提取所有数据。
  3. SqlConnection :创建数据库连接对象,使用 using 确保连接正确释放。
  4. SqlDataAdapter :使用 SQL 查询和连接对象初始化适配器。
  5. DataSet :用于接收适配器填充的数据。
  6. Fill方法 :执行查询并将结果填充到 DataSet Contacts 表中。
  7. DataTable操作 :遍历 DataTable 中的每一行并输出数据。
参数说明:
参数名 说明
connectionString 指定数据库连接的详细信息
query 要执行的SQL查询语句
adapter 负责将数据库数据加载到DataSet中
dataSet 存储从数据库加载的数据表
contactTable 从DataSet中提取的特定数据表

5.1.2 使用DataSet进行数据绑定

在Windows Forms应用程序中,可以将 DataSet 直接绑定到控件,如 DataGridView ,实现数据的动态展示。

示例代码:将DataSet绑定到DataGridView控件
// 假设已经定义好了dataGridView1控件
private void LoadContacts()
{
    string connectionString = "Server=.;Database=ContactDB;Trusted_Connection=True;";
    string query = "SELECT * FROM Contacts";

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
        DataSet dataSet = new DataSet();
        adapter.Fill(dataSet, "Contacts");

        dataGridView1.DataSource = dataSet.Tables["Contacts"];
    }
}
逻辑分析:
  • LoadContacts 方法用于加载联系人数据并绑定到 DataGridView 控件。
  • DataAdapter.Fill 将数据填充到 DataSet
  • DataSet 中的 Contacts 表设置为 DataGridView 的数据源,实现自动绑定。
绑定效果说明:
列名 数据类型 描述
ID int 联系人唯一标识
Name string 联系人姓名
Phone string 联系人电话
Email string 联系人邮箱

通过这种绑定方式,用户可以在界面上直接查看、排序和编辑数据,而无需手动编写数据刷新逻辑。

5.2 Entity Framework概述

5.2.1 ORM的基本原理与优势

ORM(Object-Relational Mapping)是一种将数据库表结构映射为面向对象语言类的技术。Entity Framework(简称EF)是微软官方推出的ORM框架,支持LINQ查询、自动追踪更改、延迟加载等高级特性。

ORM工作原理流程图:
graph LR
    A[数据库表] --> B[实体类]
    B --> C[LINQ查询]
    C --> D[EF上下文]
    D --> E[数据库操作]
EF Core的主要优势:
优势 说明
简化数据访问 不需要手动编写SQL语句
自动追踪更改 实体状态自动管理,减少错误
支持多种数据库 支持SQL Server、MySQL、PostgreSQL等
高度可扩展 支持自定义类型、查询拦截等高级功能

5.2.2 EF Core的安装与配置

要在项目中使用EF Core,首先需要安装对应的NuGet包,并配置数据库上下文。

安装步骤:
  1. 打开Visual Studio,右键项目 → 管理NuGet包。
  2. 搜索并安装以下包:
    - Microsoft.EntityFrameworkCore
    - Microsoft.EntityFrameworkCore.SqlServer
    - Microsoft.EntityFrameworkCore.Tools (用于迁移)
配置数据库上下文:
using Microsoft.EntityFrameworkCore;

public class ContactContext : DbContext
{
    public DbSet<Contact> Contacts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=.;Database=ContactDB;Trusted_Connection=True;");
    }
}

public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}
代码解释:
  • ContactContext 是EF Core的上下文类,负责管理实体对象的生命周期和数据库连接。
  • DbSet<Contact> 表示数据库中的 Contacts 表。
  • OnConfiguring 方法中使用 UseSqlServer 配置数据库连接字符串。

5.3 EF在通讯录系统中的应用

5.3.1 使用Code First模式设计数据模型

Code First模式允许开发者先定义实体类,再由EF Core自动生成数据库表结构。

示例:定义联系人实体类
public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}
创建迁移并更新数据库:
Add-Migration InitialCreate
Update-Database

上述命令将在数据库中创建 Contacts 表,并根据实体类定义字段。

5.3.2 实现数据库的自动迁移与更新

EF Core的迁移功能可以自动将模型更改同步到数据库中。

迁移流程图:
graph LR
    A[实体类变更] --> B[添加迁移]
    B --> C[生成SQL脚本]
    C --> D[更新数据库]
示例:添加一个字段并迁移
public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public string Address { get; set; }  // 新增字段
}

运行迁移命令:

Add-Migration AddAddressField
Update-Database

EF Core将自动在数据库中为 Contacts 表添加 Address 字段,无需手动编写SQL语句。

迁移优势总结:
功能 说明
版本控制 每次迁移生成一个版本脚本
自动同步 实体类与数据库结构保持一致
安全更新 支持数据迁移和字段重命名

通过EF Core的Code First和迁移功能,开发者可以专注于业务逻辑的实现,而无需频繁操作数据库结构,大大提升了开发效率和系统的可维护性。

6. 联系人管理功能模块开发(增删改查)

6.1 功能模块设计与需求分析

6.1.1 联系人信息结构设计

在开发通讯录系统时,首先需要定义联系人数据模型。一个典型的联系人应包括姓名、电话、邮箱、地址等字段。在C#中,我们通常使用实体类来表示这些信息。以下是一个简单的联系人模型定义:

public class Contact
{
    public int Id { get; set; }                // 联系人唯一标识
    public string Name { get; set; }           // 姓名
    public string PhoneNumber { get; set; }    // 电话号码
    public string Email { get; set; }          // 邮箱地址
    public string Address { get; set; }        // 地址信息
    public DateTime? Birthday { get; set; }    // 出生日期(可为空)
}

字段说明:
- Id :主键,唯一标识每个联系人。
- Name :联系人姓名,必填项。
- PhoneNumber :手机号码,格式校验需在UI层或业务逻辑层进行。
- Email :邮箱地址,支持可选字段。
- Address :地址信息,可为长文本。
- Birthday :出生日期,使用 DateTime? 表示可为空字段。

该模型将在EF Core中映射为数据库表,并通过Code First模式进行数据迁移与持久化。

6.1.2 功能流程图与操作逻辑梳理

联系人管理模块的核心功能包括: 新增(Create)、读取(Read)、更新(Update)、删除(Delete) ,简称CRUD。为了更好地理解模块流程,我们绘制如下流程图:

graph TD
    A[开始] --> B[显示联系人列表]
    B --> C{选择操作}
    C -->|新增| D[打开新增窗体]
    C -->|编辑| E[选择联系人 > 打开编辑窗体]
    C -->|删除| F[选择联系人 > 删除确认]
    C -->|查看| G[显示详细信息]
    D --> H[保存数据到数据库]
    E --> I[更新数据库记录]
    F --> J[删除数据库记录]
    G --> K[返回列表]
    H --> B
    I --> B
    J --> B
    K --> B

流程说明:
- 用户从主界面进入联系人管理模块后,首先加载联系人列表;
- 用户可选择执行新增、编辑、删除或查看详情;
- 每次操作完成后,刷新列表并返回主界面。

6.2 数据持久化实现

6.2.1 使用EF实现联系人数据的CRUD操作

我们使用Entity Framework Core作为ORM框架,来实现联系人数据的持久化。以下是一个典型的CRUD操作实现示例:

public class ContactService
{
    private readonly AppDbContext _context;

    public ContactService(AppDbContext context)
    {
        _context = context;
    }

    // 新增联系人
    public async Task AddContactAsync(Contact contact)
    {
        _context.Contacts.Add(contact);
        await _context.SaveChangesAsync();
    }

    // 获取所有联系人
    public async Task<List<Contact>> GetAllContactsAsync()
    {
        return await _context.Contacts.ToListAsync();
    }

    // 根据ID获取联系人
    public async Task<Contact> GetContactByIdAsync(int id)
    {
        return await _context.Contacts.FindAsync(id);
    }

    // 更新联系人信息
    public async Task UpdateContactAsync(Contact contact)
    {
        _context.Contacts.Update(contact);
        await _context.SaveChangesAsync();
    }

    // 删除联系人
    public async Task DeleteContactAsync(int id)
    {
        var contact = await GetContactByIdAsync(id);
        if (contact != null)
        {
            _context.Contacts.Remove(contact);
            await _context.SaveChangesAsync();
        }
    }
}

代码说明:
- AppDbContext :继承自 DbContext ,用于管理数据库连接和实体集;
- ToListAsync() SaveChangesAsync() 等方法为EF Core的异步操作接口,适用于Windows Forms中的UI线程;
- 使用 async/await 避免阻塞UI,提高响应速度。

6.2.2 异步操作与数据加载优化

在Windows Forms中,频繁的数据库操作可能导致界面卡顿。为此,我们建议使用异步加载策略。例如在窗体加载时使用 await 加载数据:

private async void ContactListForm_Load(object sender, EventArgs e)
{
    var contacts = await _contactService.GetAllContactsAsync();
    contactBindingSource.DataSource = contacts;
}

此外,我们还可以使用 Paging 分页加载,避免一次性加载过多数据,示例如下:

public async Task<List<Contact>> GetPagedContactsAsync(int pageNumber, int pageSize)
{
    return await _context.Contacts
        .Skip((pageNumber - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();
}

优化建议:
- 对大数据量表使用分页查询;
- 使用缓存机制缓存高频查询数据;
- 在EF中使用投影(Projection)减少内存处理开销。

(本章未完,下一部分见6.3节)

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:C#通讯录管理系统是一个基于C#和Windows Forms开发的桌面应用,具备联系人添加、搜索、编辑等核心功能。系统结合了面向对象编程、数据库操作、事件驱动机制及用户界面设计等关键技术,适用于学习C#高级开发和桌面应用构建。通过该项目,开发者可掌握数据结构应用、异常处理、代码组织、调试测试等实用技能,是从理论到实践的完整编程训练项目。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

更多推荐