当前位置: 首页 > news >正文

【C#实现手写Ollama服务交互,实现本地模型对话】

前言

C#手写Ollama服务交互,实现本地模型对话

最近使用C#调用OllamaSharpe库实现Ollama本地对话,然后思考着能否自己实现这个功能。经过一番查找,和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后,发送HTTP请求,获取返回结果以及一些数据处理。

基本流程

1、启动Ollama服务进程。
2、创建HttpClient对象。
3、创建请求体(参数:模型名称、提示语、是否流式生成)。
4、将请求体序列化为JSON。
5、创建HTTP请求内容。
6、发送POST请求,并确保请求成功。
7、读取并返回响应内容,并解析相应字符串。
8、返回结果。

 		//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt,Stream = false};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);// 创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");// 发送POST请求var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取并返回响应内容string responseString = await response.Content.ReadAsStringAsync();///解析相应字符串ResponseModel results = JsonSerializer.Deserialize<ResponseModel>(responseString);//返回结果return results.Response;

项目结构

OllamaClient :实现基本的对话请求、获取模型列表功能。
Model :创建模型结果的一些参数
RequestModel:请求参数模型
ResponseModel:结果参数模型,用于解析返回的结果。
MainWindow:用户界面
MainWindowViewModel:界面交互业务处理

在这里插入图片描述

案例

模型加载

在这里插入图片描述

发送聊天

在这里插入图片描述

代码

OllamaSharpe

Ollama客户端 OllamaClient

public class OllamaClient{public IEnumerable<Model> ModelList { get; set; }private readonly HttpClient _httpClient;public OllamaClient(string baseAddress = "http://localhost:11434"){_httpClient = new HttpClient{BaseAddress = new Uri(baseAddress)};ExecuteCommand("ollama list");  //启动Ollama服务}/// <summary>/// 异步生成文本/// </summary>public async Task<string> GenerateTextAsync(string model, string prompt){try{//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt,Stream = false};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);// 创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");// 发送POST请求var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取并返回响应内容string responseString = await response.Content.ReadAsStringAsync();///解析相应字符串ResponseModel results = JsonSerializer.Deserialize<ResponseModel>(responseString);//返回结果return results.Response;}catch (HttpRequestException e){throw new Exception($"Request failed: {e.Message}");}}/// <summary>/// 异步流式生成文本/// </summary>public async IAsyncEnumerable<string> StreamGenerateTextAsync(string model, string prompt){//创建请求体:模型名称、提示语、是否流式生成var request = new RequestModel{Model = model,Prompt = prompt, Stream = true};// 将请求体序列化为JSONvar json = JsonSerializer.Serialize(request);//创建HTTP请求内容var content = new StringContent(json, Encoding.UTF8, "application/json");//发送POST请求using var response = await _httpClient.PostAsync("/api/generate", content);// 确保请求成功response.EnsureSuccessStatusCode();// 读取流并解析为ResponseModelusing var stream = await response.Content.ReadAsStreamAsync();// 创建流读取器using var reader = new StreamReader(stream);// 循环读取流while (!reader.EndOfStream){// 读取一行var line = await reader.ReadLineAsync();// 如果行不为空,则解析为ResponseModel并返回if (!string.IsNullOrEmpty(line)){var partial = JsonSerializer.Deserialize<ResponseModel>(line);yield return partial.Response;}}}/// <summary>/// 异步获取本地模型列表/// </summary>public async Task<IEnumerable<Model>> ListLocalModelsAsync(){//相应请求HttpResponseMessage responseMessage = await _httpClient.GetAsync("/api/tags").ConfigureAwait(false);;//确保请求成功responseMessage.EnsureSuccessStatusCode();//读取响应string response = await responseMessage.Content.ReadAsStringAsync();//读取流并解析为LocalModelsLocalModels localModel = JsonSerializer.Deserialize<LocalModels>(response);await Task.Delay(3000);//返回结果ModelList = localModel.Models;return localModel.Models;}// <summary>/// 执行CMD指令:用于启动Ollama服务,/// </summary>public static bool ExecuteCommand(string command){// 创建一个新的进程启动信息ProcessStartInfo processStartInfo = new ProcessStartInfo{FileName = "cmd.exe",           // 设置要启动的程序为cmd.exeArguments = $"/C {command}",    // 设置要执行的命令UseShellExecute = true,         // 使用操作系统shell启动进程CreateNoWindow = false,         //不创建窗体};try{Process process = Process.Start(processStartInfo);// 启动进程process.WaitForExit();    // 等待进程退出process.Close();          // 返回是否成功执行return process.ExitCode == 0;}catch (Exception ex){Debug.WriteLine($"发生错误: {ex.Message}");// 其他异常处理return false;}}}

请求模型:RequestModel

/// <summary>
/// 请求模型
/// </summary>
public class RequestModel
{public string Model { get; set; }public string Prompt { get; set; }public bool Stream { get; set; }
}

响应模型:ResponseModel

/// <summary>
/// 响应模型
/// </summary>
public class ResponseModel
{/// <summary>/// 模型名称/// </summary>[JsonPropertyName("model")]public string Model { get; set; }/// <summary>/// 创建时间/// </summary>[JsonPropertyName("created_at")]public string CreatedTime { get; set; }/// <summary>/// 响应:返回文本/// </summary>[JsonPropertyName("response")]public string Response { get; set; }/// <summary>/// 是否结束/// </summary>[JsonPropertyName("done")]public bool Done { get; set; }/// <summary>/// 结束原因/// </summary>[JsonPropertyName("done_reason")]public string Done_Reason { get; set; }/// <summary>/// 上下文/// </summary>[JsonPropertyName("context")]public List<int> Context { get; set; }/// <summary>/// 总耗时/// </summary>[JsonPropertyName("total_duration")]public long TotalDuration { get; set; }/// <summary>/// 加载耗时/// </summary>[JsonPropertyName("load_duration")]public long LoadDuration { get; set; }/// <summary>/// 提示词评估次数/// </summary>[JsonPropertyName("prompt_eval_count")]public long PromptEvalCount { get; set; }/// <summary>/// 提示词评估耗时/// </summary>[JsonPropertyName("prompt_eval_duration")]public long PromptEvalDuration { get; set; }/// <summary>/// 评估次数/// </summary>[JsonPropertyName("eval_count")]public long EvalCount { get; set; }/// <summary>/// 评估耗时/// </summary>[JsonPropertyName("eval_duration")]public long EvalDuration { get; set; }
}

结果模型:LocalModels | Model

/// <summary>
/// 本地模型
/// </summary>
public class LocalModels
{[JsonPropertyName("models")]public IEnumerable<Model> Models { get; set; }
}
/// <summary>
/// 模型
/// </summary>
public class Model
{/// <summary>/// 模型名称/// </summary>[JsonPropertyName("name")]public string Name { get; set; }/// <summary>/// 模型名称/// </summary>[JsonPropertyName("model")]public string ModelName { get; set; }/// <summary>/// 修改时间/// </summary>[JsonPropertyName("modified_at")]public DateTime ModifiedAt { get; set; }/// <summary>/// 大小/// </summary>[JsonPropertyName("size")]public long Size { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("digest")]public string Digest { get; set; }/// <summary>/// 模型细节/// </summary>[JsonPropertyName("details")]public ModelDetails Details { get; set; }
}/// <summary>
/// 模型细节
/// </summary>
public class ModelDetails
{/// <summary>/// 父模型/// </summary>[JsonPropertyName("parent_model")]public string ParentModel { get; set; }/// <summary>/// 格式/// </summary>[JsonPropertyName("format")]public string Format { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("family")]public string Family { get; set; }/// <summary>/// /// </summary>[JsonPropertyName("families")]public List<string> Families { get; set; }/// <summary>/// 参数大小/// </summary>[JsonPropertyName("parameter_size")]public string ParameterSize { get; set; }/// <summary>/// 质量等级/// </summary>[JsonPropertyName("quantization_level")]public string QuantizationLevel { get; set; }
}

简单的界面

MainWindow

<Window.DataContext><local:MainWindowViewModel x:Name="ViewModel"/>
</Window.DataContext>
<Grid><Grid.RowDefinitions><RowDefinition Height="50"/><RowDefinition Height="*"/><RowDefinition Height="300"/></Grid.RowDefinitions><Grid Grid.Row="0"><WrapPanel VerticalAlignment="Center" Margin="5"><Label Content="模型列表" Margin="5"/><ComboBox Width="200" Margin="5" Name="ModelListBox"ItemsSource="{Binding ModelCollection}"SelectedItem="{Binding SelectedModel}"/></WrapPanel></Grid><Grid Grid.Row="1"><TextBox x:Name="OutputBox" Text="{Binding OutputText}"ScrollViewer.HorizontalScrollBarVisibility="Visible"ScrollViewer.VerticalScrollBarVisibility="Visible"/></Grid><Grid Grid.Row="2"><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="50"/></Grid.RowDefinitions><TextBox Grid.Row="0" x:Name="InputBox" Background="#AAAAAA"Text="{Binding InputText}"TextWrapping="WrapWithOverflow"ScrollViewer.VerticalScrollBarVisibility="Auto"ScrollViewer.HorizontalScrollBarVisibility="Auto" ></TextBox><WrapPanel Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5"><Button  Grid.Row="1"  Width="100" Height="30" x:Name="Btn_Submit" Command="{Binding SendQuestionCommand}">发送</Button></WrapPanel></Grid>
</Grid>

MainWindowViewModel

public class MainWindowViewModel: PropertyChangedBase
{#region 字段、属性private string _inputText = "";         //输入文本private string _outputText = "";        //输出文本private OllamaClient _ollama;            //Ollama客户端private string _selectedModel = "deepseek-r1:1.5b";     //选择模型private ObservableCollection<string> _modelCollection;  //模型列表#region 属性public ObservableCollection<string> ModelCollection{get => _modelCollection;set{if (_modelCollection != value){_modelCollection = value;OnPropertyChanged();}}}public string SelectedModel{get => _selectedModel;set{if (_selectedModel != value){_selectedModel = value;OnPropertyChanged();}}}private OllamaClient Ollama { get => _ollama; }public string OutputText{get => _outputText;set{if (_outputText != value){_outputText = value;OnPropertyChanged();}}}public string InputText{get => _inputText;set{if (_inputText != value){_inputText = value;OnPropertyChanged();}}}public ICommand SendQuestionCommand { get; set; }#endregion#endregionpublic MainWindowViewModel(){Initialze();}/// <summary>/// 初始化/// </summary>private void Initialze(){_ollama = new OllamaClient();_modelCollection = new ObservableCollection<string>();SelectedModel = "deepseek-r1:1.5b";var models = Ollama.ListLocalModelsAsync();AppendLine($"模型列表;{Environment.NewLine}");foreach (var model in models.Result){ModelCollection.Add(model.ModelName);AppendLine($"{model.ModelName}{FormatFileSize(model.Size)}\r\n");}SendQuestionCommand = new ParameterlessCommand(OnSendQuestion);}/// <summary>/// 格式化文件大小/// </summary>private string FormatFileSize(long bytes){string[] sizes = { "B", "KB", "MB", "GB", "TB" };int order = 0;while (bytes >= 1024 && order < sizes.Length - 1){order++;bytes = bytes / 1024;}return $"{bytes:0.##} {sizes[order]}";}/// <summary>/// 发送文本/// </summary>public async void OnSendQuestion(){try{AppendLine($"【用户】{InputText}\r\n\r\n");AppendLine($"【AI】\r\n\r\n");await foreach (var answerToken in Ollama.StreamGenerateTextAsync(SelectedModel, InputText)){AppendText(answerToken);}AppendLine($"\r\n");}catch (Exception ex){AppendText($"Error: {ex.Message}");}}/// <summary>/// 附加文本/// </summary>private async void AppendText(string text){Debug.Print($"{text}");OutputText += text;}/// <summary>/// 附加文本行/// </summary>private async void AppendLine(string text){Debug.Print($"{text}");OutputText += $"{text}\r\n";}
}
 /// <summary>/// 属性变更/// </summary>public class PropertyChangedBase : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

总结

案例代码实现了与Ollama的HTTP交互,通过使用HttpClient、JSON序列化和错误处理,提供了一个简洁的异步文本生成接口。适合直接调用本地Ollama服务的场景,更多功能,可以后续拓展。

相关文章:

【C#实现手写Ollama服务交互,实现本地模型对话】

前言 C#手写Ollama服务交互&#xff0c;实现本地模型对话 最近使用C#调用OllamaSharpe库实现Ollama本地对话&#xff0c;然后思考着能否自己实现这个功能。经过一番查找&#xff0c;和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后&#xff0c;发送HTTP请求&a…...

Android Glide 框架线程管理模块原理的源码级别深入分析

一、引言 在现代的 Android 应用开发中&#xff0c;图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架&#xff0c;以其高效、灵活和易用的特点受到了开发者的青睐。其中&#xff0c;线程管理模块是 Glide 框架中至关重要的一部分&#xff0c;它负责协调…...

每天记录一道Java面试题---day32

MySQL索引的数据结构、各自优劣 回答重点 B树&#xff1a;是一个平衡的多叉树&#xff0c;从根节点到每个叶子节点的高度差不超过1&#xff0c;而且同层级的节点间有指针相互连接。在B树上的常规检索&#xff0c;从根节点到叶子节点的搜索效率基本相当&#xff0c;不会出现大…...

Vue3 Pinia 符合直觉的Vue.js状态管理库

Pinia 符合直觉的Vue.js状态管理库 什么时候使用Pinia 当两个关系非常远的组件&#xff0c;要传递参数时使用Pinia组件的公共参数使用Pinia...

深度学习与大模型基础-向量

大家好&#xff01;今天我们来聊聊向量&#xff08;Vector&#xff09;。别被这个词吓到&#xff0c;其实向量在我们的生活中无处不在&#xff0c;只是我们没注意罢了。 1. 向量是什么&#xff1f; 简单来说&#xff0c;向量就是有大小和方向的量。比如你从家走到学校&#x…...

【网络编程】完成端口 IOCP

10.11 完成端口 10.11.1 基本概念 完成端口的全称是I/O 完成端口&#xff0c;英文为IOCP(I/O Completion Port) 。IOCP是一个异 步I/O 的 API, 可以高效地将I/O 事件通知给应用程序。与使用select() 或是其他异步方法不同 的是&#xff0c;一个套接字与一个完成端口关联了起来…...

《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...

管理网络安全

防火墙在 Linux 系统安全中有哪些重要的作用&#xff1f; 防火墙作为网络安全的第一道防线&#xff0c;能够根据预设的规则&#xff0c;对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问&#xff0c;只允许符合规则的流量进入系统&#xff0c;从而保护系统免受…...

明日直播|Go IoT 开发平台,开启万物智联新征程

在物联网技术飞速发展的当下&#xff0c;物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境&#xff0c;实现高效、便捷开发的有力工具。 3 月 11 日&#xff08;星期二&#xff09;19:00&#xff0c;GitCode 特别邀请独…...

系统架构设计师—系统架构设计篇—软件架构风格

文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格&#xff08;数据共享风格&#xff09;数据库系统黑板系统超文本系统 闭…...

【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)

文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...

【Zinx】Day5-Part4:Zinx 的连接属性设置

目录 Day5-Part4&#xff1a;Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4&#xff1a;Zinx 的连接属性设置 在 Zinx 当中&#xff0c;我们使用 Server 来开启服务并监听指定的端口&#xff0c;当接收到来自客户端的连接请求…...

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…...

小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡

在微信小程序中&#xff0c;事件分为 冒泡事件 和 非冒泡事件 &#xff1a; 冒泡事件&#xff1a;当一个组件的事件被触发后&#xff0c;该事件会向父节点传递&#xff1b;&#xff08;如果父节点中也绑定了一个事件&#xff0c;父节点事件也会被触发&#xff0c;也就是说子组…...

全球首款 5G-A 人形机器人发布

全球首款 5G-A 人形机器人于世界移动通信大会&#xff08;MWC2025&#xff09;上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍&#xff1a; 名称与背景 名称9&#xff1a;这款人形机器人名为 “夸父”&#xff0c;是中国移动、华为与乐聚机器人在 GTI 平台…...

Tomcat 新手入门指南

Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器&#xff0c;广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南&#xff0c;帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...

Flink-DataStreamAPI-生成水印

下面我们将学习Flink提供的用于处理事件时间戳和水印的API&#xff0c;也会介绍有关事件时间、流转时长和摄取时间&#xff0c;下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间&#xff0c;Flink需要知道事件时间戳&#xff0c;这意味着流中的每个元素都需要…...

【单片机】ARM 处理器简介

ARM 公司简介 ARM&#xff08;Advanced RISC Machine&#xff09; 是英国 ARM 公司&#xff08;原 Acorn RISC Machine&#xff09; 开发的一种精简指令集&#xff08;RISC&#xff09; 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性&#xff0c;成为嵌入式系统、移动…...

Flutter——最详细原生交互(MethodChannel、EventChannel、BasicMessageChannel)使用教程

MethodChannel&#xff08;方法通道&#xff09; 用途&#xff1a;实现 双向通信&#xff0c;用于调用原生平台提供的 API 并获取返回结果。 场景&#xff1a;适合一次性操作&#xff0c;如调用相机、获取设备信息等。 使用步骤&#xff1a; Flutter 端&#xff1a;通过 Meth…...

Kafka常用指令(详细)

Kafka常用指令&#xff08;详细&#xff09; 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon&#xff0c;窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统

核心速览 研究背景 ​​研究问题​​&#xff1a;这篇文章要解决的问题是当前大型语言模型&#xff08;LLMs&#xff09;在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色&#xff0c;但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成&#xff08;RA…...

前端打包工具简单介绍

前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry&#xff08;入口&#xff09; 指定应用的起点文件&#xff0c;比如 src/index.js。 Module&#xff08;模块&#xff09; Webpack 把项目当作模块图&#xff0c;模块可以是 JS、CSS、图片等…...

.Net Framework 4/C# 面向对象编程进阶

一、继承 (一)使用继承 子类可以继承父类原有的属性和方法,也可以增加原来父类不具备的属性和方法,或者直接重写父类中的某些方法。 C# 中使用“:”来表示两个类的继承。子类不能访问父类的私有成员,但是可以访问其公有成员,即只要使用 public 声明类成员,就既可以让一…...