欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在C#中基于Semantic?Kernel的檢索增強(qiáng)生成(RAG)實(shí)踐記錄

 更新時(shí)間:2024年10月21日 08:57:58   作者:dax.net  
SemanticKernel是一個(gè)用于集成和操作大語(yǔ)言模型的應(yīng)用程序框架,支持C#、Python和Java等多種編程語(yǔ)言,通過(guò)SemanticKernel,開(kāi)發(fā)者可以輕松構(gòu)建基于最新AI技術(shù)的應(yīng)用程序

Semantic Kernel簡(jiǎn)介

玩過(guò)大語(yǔ)言模型(LLM)的都知道OpenAI,然后微軟Azure也提供了OpenAI的服務(wù):Azure OpenAI,只需要申請(qǐng)到API Key,就可以使用這些AI服務(wù)。使用方式可以是通過(guò)在線(xiàn)Web頁(yè)面直接與AI聊天,也可以調(diào)用AI的API服務(wù),將AI的能力集成到自己的應(yīng)用程序中。不過(guò)這些服務(wù)都是在線(xiàn)提供的,都會(huì)需要根據(jù)token計(jì)費(fèi),所以不僅需要依賴(lài)互聯(lián)網(wǎng),而且在使用上會(huì)有一定成本。于是,就出現(xiàn)了像Ollama這樣的本地大語(yǔ)言模型服務(wù),只要你的電腦足夠強(qiáng)悍,應(yīng)用場(chǎng)景允許的情況下,使用本地大語(yǔ)言模型也是一個(gè)不錯(cuò)的選擇。

既然有這么多AI服務(wù)可以選擇,那如果在我的應(yīng)用程序中需要能夠很方便地對(duì)接不同的AI服務(wù),應(yīng)該怎么做呢?這就是Semantic Kernel的基本功能,它是一個(gè)基于大語(yǔ)言模型開(kāi)發(fā)應(yīng)用程序的框架,可以讓你的應(yīng)用程序更加方便地集成大語(yǔ)言模型。Semantic Kernel可用于輕松生成 AI 代理并將最新的 AI 模型集成到 C#、Python 或 Java 代碼庫(kù)中。因此,它雖然在.NET AI生態(tài)中扮演著非常重要的角色,但它是支持多編程語(yǔ)言跨平臺(tái)的應(yīng)用開(kāi)發(fā)套件。

Semantic Kernel主要包含以下這些核心概念:

  • 連接(Connection):與外部 AI 服務(wù)和數(shù)據(jù)源交互,比如在應(yīng)用程序中實(shí)現(xiàn)Open AI和Ollama的無(wú)縫整合
  • 插件(Plugins):封裝應(yīng)用程序可以使用的功能,比如增強(qiáng)提示詞功能,為大語(yǔ)言模型提供更多的上下文信息
  • 規(guī)劃器(Planner):根據(jù)用戶(hù)行為編排執(zhí)行計(jì)劃和策略
  • 內(nèi)存(Memory):抽象并簡(jiǎn)化 AI 應(yīng)用程序的上下文管理,比如文本向量(Text Embedding)的存儲(chǔ)等

有關(guān)Semantic Kernel的具體介紹可以參考微軟官方文檔。

演練:通過(guò)Semantic Kernel使用Microsoft Azure OpenAI Service

話(huà)不多說(shuō),直接實(shí)操。這個(gè)演練的目的,就是使用部署在A(yíng)zure上的gpt-4o大語(yǔ)言模型來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的問(wèn)答系統(tǒng)。

微軟于2024年10月21日終止面向個(gè)人用戶(hù)的Azure OpenAI服務(wù),企業(yè)用戶(hù)仍能繼續(xù)使用。參考:https://finance.sina.com.cn/roll/2024-10-18/doc-incsymyx4982064.shtml

在A(yíng)zure中部署大語(yǔ)言模型

登錄Azure Portal,新建一個(gè)Azure AI service,然后點(diǎn)擊Go to Azure OpenAI Studio,進(jìn)入OpenAI Studio:

進(jìn)入后,在左側(cè)側(cè)邊欄的共享資源部分,選擇部署標(biāo)簽頁(yè),然后在模型部署頁(yè)面,點(diǎn)擊部署模型按鈕,在下拉的菜單中,選擇部署基本模型

選擇模型對(duì)話(huà)框中,選擇gpt-4o,然后點(diǎn)擊確認(rèn)按鈕:

在彈出的對(duì)話(huà)框部署模型 gpt-4o中,給模型取個(gè)名字,然后直接點(diǎn)擊部署按鈕,如果希望對(duì)模型版本、安全性等做一些設(shè)置,也可以點(diǎn)擊自定義按鈕展開(kāi)選項(xiàng)。

部署成功后,就可以在模型部署頁(yè)面的列表中看到已部署模型的版本以及狀態(tài):

點(diǎn)擊新部署的模型的名稱(chēng),進(jìn)入模型詳細(xì)信息頁(yè)面,在頁(yè)面的終結(jié)點(diǎn)部分,把目標(biāo)URI密鑰復(fù)制下來(lái),待會(huì)要用。目標(biāo)URI只需要復(fù)制主機(jī)名部分即可,比如https://qingy-m2e0gbl3-eastus.openai.azure.com這樣:

在C#中使用Semantic Kernel實(shí)現(xiàn)問(wèn)答應(yīng)用

首先創(chuàng)建一個(gè)控制臺(tái)應(yīng)用程序,然后添加Microsoft.SemanticKernel NuGet包的引用:

$ dotnet new console --name ChatApp
$ dotnet add package Microsoft.SemanticKernel

然后編輯Program.cs文件,加入下面的代碼:

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using System.Text;
var apikey = Environment.GetEnvironmentVariable("azureopenaiapikey")!;
// 初始化Semantic Kernel
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        "gpt-4", 
        "https://qingy-m2e0gbl3-eastus.openai.azure.com", 
        apikey)
    .Build();
// 創(chuàng)建一個(gè)對(duì)話(huà)完成服務(wù)以及對(duì)話(huà)歷史對(duì)象,用來(lái)保存對(duì)話(huà)歷史,以便后續(xù)為大模型
// 提供對(duì)話(huà)上下文信息。
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var chat = new ChatHistory("你是一個(gè)AI助手,幫助人們查找信息和回答問(wèn)題");
StringBuilder chatResponse = new();
while (true)
{
    Console.Write("請(qǐng)輸入問(wèn)題>> ");
    // 將用戶(hù)輸入的問(wèn)題添加到對(duì)話(huà)中
    chat.AddUserMessage(Console.ReadLine()!);
    chatResponse.Clear();
    // 獲取大語(yǔ)言模型的反饋,并將結(jié)果逐字輸出
    await foreach (var message in
                   chatCompletionService.GetStreamingChatMessageContentsAsync(chat))
    {
        // 輸出當(dāng)前獲取的結(jié)果字符串
        Console.Write(message);
        // 將輸出內(nèi)容添加到臨時(shí)變量中
        chatResponse.Append(message.Content);
    }
    Console.WriteLine();
    // 在進(jìn)入下一次問(wèn)答之前,將當(dāng)前回答結(jié)果添加到對(duì)話(huà)歷史中,為大語(yǔ)言模型提供問(wèn)答上下文
    chat.AddAssistantMessage(chatResponse.ToString());
    Console.WriteLine();
}

在上面的代碼中,需要將你的API Key和終結(jié)點(diǎn)URI配置進(jìn)去,為了安全性,這里我使用環(huán)境變量保存API Key,然后由程序讀入。為了讓大語(yǔ)言模型能夠了解在一次對(duì)話(huà)中,我和它之間都討論了什么內(nèi)容,在代碼中,使用一個(gè)StringBuilder臨時(shí)保存了當(dāng)前對(duì)話(huà)的應(yīng)答結(jié)果,然后將這個(gè)結(jié)果又通過(guò)Semantic Kernel的AddAssistantMessage方法加回到對(duì)話(huà)中,以便在下一次對(duì)話(huà)中,大語(yǔ)言模型能夠知道我們?cè)诹氖裁丛?huà)題。

比如下面的例子中,在第二次提問(wèn)時(shí)我問(wèn)到“有那幾次遷徙?”,AI能知道我是在說(shuō)人類(lèi)歷史上的大遷徙,然后將我想要的答案列舉出來(lái):

到這里,一個(gè)簡(jiǎn)單的基于gpt-4o的問(wèn)答應(yīng)用就完成了,它的工作流程大致如下:

AI能回答所有的問(wèn)題嗎?

由于這里使用的gpt-4o大語(yǔ)言模型是在今年5月份發(fā)布的,而大語(yǔ)言模型都是基于現(xiàn)有數(shù)據(jù)經(jīng)過(guò)訓(xùn)練得到的,所以,它應(yīng)該不會(huì)知道5月份以后的事情,遇到這樣的問(wèn)題,AI只能回答不知道,或者給出一個(gè)比較離譜的答案:

你或許會(huì)想,那我將這些知識(shí)或者新聞文章下載下來(lái),然后基于上面的代碼,將這些信息先添加到對(duì)話(huà)歷史中,讓大語(yǔ)言模型能夠了解上下文,這樣回答問(wèn)題的時(shí)候準(zhǔn)確率不是提高了嗎?這個(gè)思路是對(duì)的,可以在進(jìn)行問(wèn)答之前,將新聞的文本信息添加到對(duì)話(huà)歷史中:

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using System.Text;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Memory;
using Microsoft.SemanticKernel.Text;
#pragma warning disable SKEXP0010, SKEXP0001, SKEXP0050
const string CollectionName = "LatestNews";
var apikey = Environment.GetEnvironmentVariable("azureopenaiapikey")!;
// 初始化Semantic Kernel
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        "gpt-4", 
        "https://qingy-m2e0gbl3-eastus.openai.azure.com", 
        apikey)
    .Build();
// 創(chuàng)建文本向量生成服務(wù)
var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService(
    "text-embedding-3-small",
    "https://qingy-m2e0gbl3-eastus.openai.azure.com",
    apikey);
// 創(chuàng)建用于保存文本向量的內(nèi)存向量數(shù)據(jù)庫(kù)
var memory = new MemoryBuilder()
    .WithMemoryStore(new VolatileMemoryStore())
    .WithTextEmbeddingGeneration(textEmbeddingGenerationService)
    .Build();
// 從外部文件以Markdown格式讀入內(nèi)容,然后根據(jù)語(yǔ)義產(chǎn)生多個(gè)段落
var markdownContent = await File.ReadAllTextAsync(@"input.md");
var paragraphs =
    TextChunker.SplitMarkdownParagraphs(
        TextChunker.SplitMarkDownLines(markdownContent.Replace("\r\n", " "), 128),
        64);
// 將各個(gè)段落進(jìn)行量化并保存到向量數(shù)據(jù)庫(kù)
for (var i = 0; i < paragraphs.Count; i++)
{
    await memory.SaveInformationAsync(CollectionName, paragraphs[i], $"paragraph{i}");
}
// 創(chuàng)建一個(gè)對(duì)話(huà)完成服務(wù)以及對(duì)話(huà)歷史對(duì)象,用來(lái)保存對(duì)話(huà)歷史,以便后續(xù)為大模型
// 提供對(duì)話(huà)上下文信息。
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var chat = new ChatHistory("你是一個(gè)AI助手,幫助人們查找信息和回答問(wèn)題");
StringBuilder additionalInfo = new();
StringBuilder chatResponse = new();
while (true)
{
    Console.Write("請(qǐng)輸入問(wèn)題>> ");
    var question = Console.ReadLine()!;
    additionalInfo.Clear();
    // 從向量數(shù)據(jù)庫(kù)中找到跟提問(wèn)最為相近的3條信息,將其添加到對(duì)話(huà)歷史中
    await foreach (var hit in memory.SearchAsync(CollectionName, question, limit: 3))
    {
        additionalInfo.AppendLine(hit.Metadata.Text);
    }
    var contextLinesToRemove = -1;
    if (additionalInfo.Length != 0)
    {
        additionalInfo.Insert(0, "以下是一些附加信息:");
        contextLinesToRemove = chat.Count;
        chat.AddUserMessage(additionalInfo.ToString());
    }
    // 將用戶(hù)輸入的問(wèn)題添加到對(duì)話(huà)中
    chat.AddUserMessage(question);
    chatResponse.Clear();
    // 獲取大語(yǔ)言模型的反饋,并將結(jié)果逐字輸出
    await foreach (var message in
                   chatCompletionService.GetStreamingChatMessageContentsAsync(chat))
    {
        // 輸出當(dāng)前獲取的結(jié)果字符串
        Console.Write(message);
        // 將輸出內(nèi)容添加到臨時(shí)變量中
        chatResponse.Append(message.Content);
    }
    Console.WriteLine();
    // 在進(jìn)入下一次問(wèn)答之前,將當(dāng)前回答結(jié)果添加到對(duì)話(huà)歷史中,為大語(yǔ)言模型提供問(wèn)答上下文
    chat.AddAssistantMessage(chatResponse.ToString());
    // 將當(dāng)次問(wèn)題相關(guān)的內(nèi)容從對(duì)話(huà)歷史中移除
    if (contextLinesToRemove >= 0) chat.RemoveAt(contextLinesToRemove);
    Console.WriteLine();
}

但是這樣做,會(huì)造成下面的異常信息:

這個(gè)問(wèn)題其實(shí)就跟大語(yǔ)言模型的Context Window有關(guān)。當(dāng)今所有的大語(yǔ)言模型在一次數(shù)據(jù)處理上都有一定的限制,這個(gè)限制就是Context Window,在這個(gè)例子中,我們的模型一次最多處理12萬(wàn)8千個(gè)token(token是大語(yǔ)言模型的數(shù)據(jù)處理單元,它可以是一個(gè)詞組,一個(gè)單詞或者是一個(gè)字符),而我們卻輸入了147,845個(gè)token,于是就報(bào)錯(cuò)了。很明顯,我們應(yīng)該減少傳入的數(shù)據(jù)量,但這樣又沒(méi)辦法把完整的新聞文章信息發(fā)送給大語(yǔ)言模型。此時(shí)就要用到“檢索增強(qiáng)生成(RAG)”。

Semantic Kernel的檢索增強(qiáng)生成(RAG)實(shí)踐

 其實(shí),并不一定非要把整篇新聞文章發(fā)給大語(yǔ)言模型,可以換個(gè)思路:只需要在新聞文章中摘出跟提問(wèn)相關(guān)的內(nèi)容發(fā)送給大語(yǔ)言模型就可以了,這樣就可以大大減小需要發(fā)送到大語(yǔ)言模型的token數(shù)量。所以,這里就出現(xiàn)了額外的一些步驟:

  • 對(duì)大量的文檔進(jìn)行預(yù)處理,將文本信息量化并保存下來(lái)(Text Embedding)
  • 在提出新問(wèn)題時(shí),根據(jù)問(wèn)題語(yǔ)義,從保存的文本量化信息(Embeddings)中,找到與問(wèn)題相關(guān)的信息
  • 將這些信息發(fā)送給大語(yǔ)言模型,并從大語(yǔ)言模型獲得應(yīng)答
  • 將結(jié)果反饋給調(diào)用方

流程大致如下:

虛線(xiàn)灰色框中就是檢索增強(qiáng)生成(RAG)相關(guān)流程,這里就不針對(duì)每個(gè)標(biāo)號(hào)一一說(shuō)明了,能夠理解上面所述的4個(gè)大的步驟,就很好理解這張圖中的整體流程。下面我們直接使用Semantic Kernel,通過(guò)RAG來(lái)增強(qiáng)模型應(yīng)答。

首先,在A(yíng)zure OpenAI Studio中,按照上文的步驟,部署一個(gè)text-embedding-3-small的模型,同樣將終結(jié)點(diǎn)URI和API Key記錄下來(lái),然后,在項(xiàng)目中添加Microsoft.SemanticKernel.Plugins.Memory NuGet包的引用,因?yàn)槲覀兇蛩阆仁褂没趦?nèi)存的文本向量數(shù)據(jù)庫(kù)來(lái)運(yùn)行我們的代碼。Semantic Kernel支持多種向量數(shù)據(jù)庫(kù),比如Sqlite,Azure AI Search,Chroma,Milvus,Pinecone,Qdrant,Weaviate等等。在添加引用的時(shí)候,需要使用--prerelease參數(shù),因?yàn)?code>Microsoft.SemanticKernel.Plugins.Memory包目前還處于alpha階段。

將上面的代碼改成下面的形式:

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using System.Text;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Memory;
using Microsoft.SemanticKernel.Text;
#pragma warning disable SKEXP0010, SKEXP0001, SKEXP0050
const string CollectionName = "LatestNews";
var apikey = Environment.GetEnvironmentVariable("azureopenaiapikey")!;
// 初始化Semantic Kernel
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        "gpt-4", 
        "https://qingy-m2e0gbl3-eastus.openai.azure.com", 
        apikey)
    .Build();
// 創(chuàng)建文本向量生成服務(wù)
var textEmbeddingGenerationService = new AzureOpenAITextEmbeddingGenerationService(
    "text-embedding-3-small",
    "https://qingy-m2e0gbl3-eastus.openai.azure.com",
    apikey);
// 創(chuàng)建用于保存文本向量的內(nèi)存向量數(shù)據(jù)庫(kù)
var memory = new MemoryBuilder()
    .WithMemoryStore(new VolatileMemoryStore())
    .WithTextEmbeddingGeneration(textEmbeddingGenerationService)
    .Build();
// 從外部文件以Markdown格式讀入內(nèi)容,然后根據(jù)語(yǔ)義產(chǎn)生多個(gè)段落
var markdownContent = await File.ReadAllTextAsync(@"input.md");
var paragraphs =
    TextChunker.SplitMarkdownParagraphs(
        TextChunker.SplitMarkDownLines(markdownContent.Replace("\r\n", " "), 128),
        64);
// 將各個(gè)段落進(jìn)行量化并保存到向量數(shù)據(jù)庫(kù)
for (var i = 0; i < paragraphs.Count; i++)
{
    await memory.SaveInformationAsync(CollectionName, paragraphs[i], $"paragraph{i}");
}
// 創(chuàng)建一個(gè)對(duì)話(huà)完成服務(wù)以及對(duì)話(huà)歷史對(duì)象,用來(lái)保存對(duì)話(huà)歷史,以便后續(xù)為大模型
// 提供對(duì)話(huà)上下文信息。
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var chat = new ChatHistory("你是一個(gè)AI助手,幫助人們查找信息和回答問(wèn)題");
StringBuilder additionalInfo = new();
StringBuilder chatResponse = new();
while (true)
{
    Console.Write("請(qǐng)輸入問(wèn)題>> ");
    var question = Console.ReadLine()!;
    additionalInfo.Clear();
    // 從向量數(shù)據(jù)庫(kù)中找到跟提問(wèn)最為相近的3條信息,將其添加到對(duì)話(huà)歷史中
    await foreach (var hit in memory.SearchAsync(CollectionName, question, limit: 3))
    {
        additionalInfo.AppendLine(hit.Metadata.Text);
    }
    var contextLinesToRemove = -1;
    if (additionalInfo.Length != 0)
    {
        additionalInfo.Insert(0, "以下是一些附加信息:");
        contextLinesToRemove = chat.Count;
        chat.AddUserMessage(additionalInfo.ToString());
    }
    // 將用戶(hù)輸入的問(wèn)題添加到對(duì)話(huà)中
    chat.AddUserMessage(question);
    chatResponse.Clear();
    // 獲取大語(yǔ)言模型的反饋,并將結(jié)果逐字輸出
    await foreach (var message in
                   chatCompletionService.GetStreamingChatMessageContentsAsync(chat))
    {
        // 輸出當(dāng)前獲取的結(jié)果字符串
        Console.Write(message);
        // 將輸出內(nèi)容添加到臨時(shí)變量中
        chatResponse.Append(message.Content);
    }
    Console.WriteLine();
    // 在進(jìn)入下一次問(wèn)答之前,將當(dāng)前回答結(jié)果添加到對(duì)話(huà)歷史中,為大語(yǔ)言模型提供問(wèn)答上下文
    chat.AddAssistantMessage(chatResponse.ToString());
    // 將當(dāng)次問(wèn)題相關(guān)的內(nèi)容從對(duì)話(huà)歷史中移除
    if (contextLinesToRemove >= 0) chat.RemoveAt(contextLinesToRemove);
    Console.WriteLine();
}

重新運(yùn)行程序,然后提出同樣的問(wèn)題,可以看到,現(xiàn)在的答案就正確了:

 現(xiàn)在看看向量數(shù)據(jù)庫(kù)中到底有什么。新添加一個(gè)對(duì)Microsoft.SemanticKernel.Connectors.Sqlite NuGet包的引用,然后,將上面代碼的:

.WithMemoryStore(new VolatileMemoryStore())

改為:

.WithMemoryStore(await SqliteMemoryStore.ConnectAsync("vectors.db"))

重新運(yùn)行程序,執(zhí)行成功后,在bin\Debug\net8.0目錄下,可以找到vectors.db文件,用Sqlite查看工具(我用的是SQLiteStudio)打開(kāi)數(shù)據(jù)庫(kù)文件,可以看到下面的表和數(shù)據(jù):

Metadata字段保存的就是每個(gè)段落的原始數(shù)據(jù)信息,而Embedding字段則是文本向量,其實(shí)它就是一系列的浮點(diǎn)值,代表著文本之間在語(yǔ)義上的距離。

使用基于Ollama的本地大語(yǔ)言模型

Semantic Kernel現(xiàn)在已經(jīng)可以支持Ollama本地大語(yǔ)言模型了,雖然它目前也還是預(yù)覽版??梢栽陧?xiàng)目中通過(guò)添加Microsoft.SemanticKernel.Connectors.Ollama NuGet包來(lái)體驗(yàn)。建議安裝最新版本的Ollama,然后,下載兩個(gè)大語(yǔ)言模型,一個(gè)是Chat Completion類(lèi)型的,另一個(gè)是Text Embedding類(lèi)型的。我選擇了llama3.2:3bmxbai-embed-large這兩個(gè)模型:

代碼上只需要將Azure OpenAI替換為Ollama即可:

// 初始化Semantic Kernel
var kernel = Kernel.CreateBuilder()
    .AddOllamaChatCompletion(
        "llama3.2:3b", 
        new Uri("http://localhost:11434"))
    .Build();
// 創(chuàng)建文本向量生成服務(wù)
var textEmbeddingGenerationService = new OllamaTextEmbeddingGenerationService(
    "mxbai-embed-large:latest", 
    new Uri("http://localhost:11434"));

總結(jié)

通過(guò)本文的介紹,應(yīng)該可以對(duì)Semantic Kernel、RAG以及在C#中的應(yīng)用有一定的了解,雖然沒(méi)有涉及原理性的內(nèi)容,但基本已經(jīng)可以在應(yīng)用層面上提供一定的參考價(jià)值。Semantic Kernel雖然有些Plugins還處于預(yù)覽階段,但通過(guò)本文的介紹,我們已經(jīng)可以看到它的強(qiáng)大功能,比如,允許我們很方便地接入各種流行的向量數(shù)據(jù)庫(kù),也允許我們很方便地切換到不同的AI大語(yǔ)言模型服務(wù),在A(yíng)I的應(yīng)用集成上,Semantic Kernel發(fā)揮著重要的作用。

參考

本文部分內(nèi)容參考了微軟官方文檔《Demystifying Retrieval Augmented Generation with .NET》,代碼也部分參考了文中內(nèi)容。文章介紹得更為詳細(xì),建議有興趣的讀者移步閱讀。

到此這篇關(guān)于在C#中基于Semantic Kernel的檢索增強(qiáng)生成(RAG)實(shí)踐的文章就介紹到這了,更多相關(guān)C#檢索增強(qiáng)生成內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#程序員應(yīng)該養(yǎng)成的程序性能優(yōu)化寫(xiě)法

    C#程序員應(yīng)該養(yǎng)成的程序性能優(yōu)化寫(xiě)法

    工作和生活中經(jīng)??梢钥吹揭恍┏绦蛟?寫(xiě)代碼的時(shí)候只關(guān)注代碼的邏輯性,而不考慮運(yùn)行效率,其實(shí)這對(duì)大多數(shù)程序猿來(lái)說(shuō)都是沒(méi)有問(wèn)題的,不過(guò)作為一只有理想的CodeMonkey,我還是希望給大家分享一些性能優(yōu)化心得
    2017-08-08
  • C#索引屬性用法實(shí)例分析

    C#索引屬性用法實(shí)例分析

    這篇文章主要介紹了C#索引屬性用法,實(shí)例分析了C#聲明索引屬性的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • 基于WPF實(shí)現(xiàn)瀑布流控件

    基于WPF實(shí)現(xiàn)瀑布流控件

    這篇文章主要介紹了如何基于WPF實(shí)現(xiàn)簡(jiǎn)單的瀑布流控件,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定幫助,需要的小伙伴可以參考一下
    2024-02-02
  • C#實(shí)現(xiàn)串口示波器

    C#實(shí)現(xiàn)串口示波器

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)串口示波器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#生成餅形圖及添加文字說(shuō)明實(shí)例代碼

    C#生成餅形圖及添加文字說(shuō)明實(shí)例代碼

    這篇文章主要介紹了C#生成餅形圖及添加文字說(shuō)明的方法,非常實(shí)用的功能,需要的朋友可以參考下
    2014-07-07
  • C#使用StreamWriter寫(xiě)入文件的方法

    C#使用StreamWriter寫(xiě)入文件的方法

    這篇文章主要介紹了C#使用StreamWriter寫(xiě)入文件的方法,涉及C#中StreamWriter類(lèi)操作文件的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • C# WORD操作實(shí)現(xiàn)代碼

    C# WORD操作實(shí)現(xiàn)代碼

    在當(dāng)前項(xiàng)目開(kāi)發(fā)過(guò)程中,客戶(hù)有根據(jù)數(shù)據(jù)庫(kù)數(shù)據(jù)生成WORD文檔的需求,在和同事溝通的過(guò)程中,找到了兩個(gè)解決方案
    2009-04-04
  • C#運(yùn)算符之與,或,異或及移位運(yùn)算小結(jié)

    C#運(yùn)算符之與,或,異或及移位運(yùn)算小結(jié)

    本文是對(duì)C#中的與,或,異或及移位運(yùn)算進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-10-10
  • C#使用IronPython庫(kù)調(diào)用Python腳本

    C#使用IronPython庫(kù)調(diào)用Python腳本

    這篇文章介紹了C#使用IronPython庫(kù)調(diào)用Python腳本的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C#用Topshelf創(chuàng)建Windows服務(wù)的步驟分享

    C#用Topshelf創(chuàng)建Windows服務(wù)的步驟分享

    這篇文章主要給大家介紹了關(guān)于C#如何利用Topshelf創(chuàng)建Windows服務(wù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05

最新評(píng)論