From 30653a7837f643c22478986fc9be7b315b2bcba7 Mon Sep 17 00:00:00 2001 From: bicijinlian Date: Tue, 6 May 2025 19:35:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docs/多语言笔记.0.导航目录.ipynb | 24 +- ...言笔记.1.3.混合使用多种语言.md | 314 ------------ ...言笔记.2.1.操作数据库-SQL内核.md | 458 ------------------ Docs/多语言笔记.5.1.使用扩展库.md | 112 ----- Docs/多语言笔记.6.1.共享变量.md | 209 -------- ...言笔记.7.1.运行xUnit单元测试.md | 106 ---- 6 files changed, 6 insertions(+), 1217 deletions(-) delete mode 100644 Docs/多语言笔记.1.3.混合使用多种语言.md delete mode 100644 Docs/多语言笔记.2.1.操作数据库-SQL内核.md delete mode 100644 Docs/多语言笔记.5.1.使用扩展库.md delete mode 100644 Docs/多语言笔记.6.1.共享变量.md delete mode 100644 Docs/多语言笔记.7.1.运行xUnit单元测试.md diff --git a/Docs/多语言笔记.0.导航目录.ipynb b/Docs/多语言笔记.0.导航目录.ipynb index 86c3e1b..8bc6ef0 100644 --- a/Docs/多语言笔记.0.导航目录.ipynb +++ b/Docs/多语言笔记.0.导航目录.ipynb @@ -1,25 +1,13 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "id": "b1dedd01", - "metadata": { - "polyglot_notebook": { - "kernelName": "csharp" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "导航目录结构\r\n" - ] - } - ], + "cell_type": "markdown", + "id": "a1287583", + "metadata": {}, "source": [ - "Console.WriteLine(\"导航目录结构\");" + "目录结构\n", + "=======\n", + "-------" ] } ], diff --git a/Docs/多语言笔记.1.3.混合使用多种语言.md b/Docs/多语言笔记.1.3.混合使用多种语言.md deleted file mode 100644 index 052541f..0000000 --- a/Docs/多语言笔记.1.3.混合使用多种语言.md +++ /dev/null @@ -1,314 +0,0 @@ -# 混合使用多语言并共享变量 -混合使用多种语言(C#、F#、Powershell、SQL、KQL、Python、Html、JavaScript、JavaScript、Mermaind等语言),是多语言笔记的最大特性,并且支持各语言之间共享变量这一创新功能。 -## 语言及共享变量的支持情况 -| 语言 | 变量共享 | -| ---- | ---- | -| C# | 支持 | -| F# | 支持 | -| PowerShell | 支持 | -| JavaScript | 支持 | -| SQL | 支持 | -| KQL | 支持 | -| Python | 支持 | -| R | 支持 | -| HTML | 不支持 | -| Mermaid | 不支持 | -## 初始化 -```C# -//全局初始化 -#!import "./Base.ipynb" - -//共享 -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -``` -## 使用 SQL(SQLite为例) -+ 引用NuGet包 -```C# -#r "nuget:Microsoft.DotNet.Interactive.SQLite,*-*" -``` -+ 连接 SQL内核(使用 `#!connect` 魔法命令) -```C# -/* 简单使用 - - #!connect sqlite --kernel-name SQLiteSharedKernel --connection-string "Data Source=.\assets\database\study.db;" -*/ - -//优化方法 -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SQLiteSharedKernel"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect sqlite --kernel-name {magicCommandKernelName} --connection-string \"{SharedDbConnect.SQLiteConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -+ 使用SQL内核(SQL语句操作数据库) -```C# -#!sql-SQLiteSharedKernel - ---查询年龄最大的5名学生 -SELECT * FROM Student order by Age Desc LIMIT 5; - ---查询学生总数 -SELECT COUNT(*) AS Count FROM Student; -``` -## 使用 KQL(效果图) -因为环境比较难搭建,用效果图代替。 - -![KQL效果](./assets/images/KQL_Samples.jpg) -## 使用 Raw Value Storage -使用value内核,可以方便的管理共享文本数据。 -```C# -#!value --name SharedDataFromValueKernel --from-file ./shared/file/data.json -``` -## C# -### 一般使用 -```C# -var student = new {Id=1, Name="张三",Age=18}; -student.Display(); -``` -### 使用Value内核共享的变量 -```C# -#!set --name fromSharedFileData --value @value:SharedDataFromValueKernel - -fromSharedFileData.Display(); -``` -### 共享变量 -使用C#查询数据库中的数据,共享出来,给其它语言(F#、html、js等使用) -```C# -#r "nuget:Microsoft.Data.SqlClient" -#r "nuget:Microsoft.Data.Sqlite" - -using System.Data; -using System.Data.Common; -using System.Data.SqlTypes; - -using Microsoft.Data.SqlClient; -using Microsoft.Data.Sqlite; - -//使用 Ado.Net 从SQLite中获取数据,再共享出去 - -//查询数据 -var SharedStudents = new List(); -{ - DataSet ds = new DataSet(); - using(var sqlConnection = new SqliteConnection(SharedDbConnect.SQLiteConnectionString)) - { - sqlConnection.Open(); - - var querySql = - """ - SELECT * FROM Student LIMIT 5; - """; - var cmd = sqlConnection.CreateCommand(); - cmd.CommandType = CommandType.Text; - cmd.CommandText = querySql; - - using (var reader = await cmd.ExecuteReaderAsync()) - { - //循环输出行数据 - while (await reader.ReadAsync()) - { - var user = new Student() - { - Id = reader.GetFieldValue("Id"), - Name = reader.GetFieldValue("Name"), - Age = reader.GetFieldValue("Age"), - }; - - SharedStudents.Add(user); - } - } - - sqlConnection.Close(); - sqlConnection.Dispose(); - } -} - -//共享数据:默认SharedStudents已共享,其它语言引用即可 -SharedStudents.Display(); -``` -## F# -### 简单示例 -```C# -printfn "Hello World from F#" -``` -### 使用C#共享数据 -```C# -#!set --value @csharp:SharedStudents --name SharedStudents - -SharedStudents -``` -## Powershell -```C# -#!powershell -Write-Host "hellow powershell" -``` -## 使用Python -+ 前提:系统要安装Python环境,推荐使用Anaconda安装,直接安装Python也可以 - -+ 作用:使多语言笔记,直接支持 Python语言; -+ 连接到 Python 内核 -```C# -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; - -//引入Python内核:使用C# 执行引入语句 -if(Kernel.Root.FindKernelByName("pythonkernel2") == null) -{ - //Console.WriteLine("正在导入Python内核...."); - var importPythonkernel = "#!connect jupyter --kernel-name pythonkernel2 --kernel-spec python3"; - await Kernel.Root.SendAsync(new SubmitCode( importPythonkernel, "csharp")); - Console.WriteLine("Python内核导入完成"); -} -else -{ - Console.WriteLine("Python内核已经导入"); -} -``` -+ 使用 Python -```C# -# 明确指定内核:优先级高于 "单元格选择的内核" -#!pythonkernel2 - -#!set --value @csharp:SharedStudents --name SharedStudents - -print("你好,我是 Ployglot Notebooks 使用 Python语言内核,打印的内容!") -``` -## 在 Python 中使用C#共享变量 -```C# -#!pythonkernel2 - -#!set --value @csharp:SharedStudents --name SharedStudents -print(SharedStudents) -``` -## 使用 html -```C# - - - - - - - 完整html文档 - - -
-

使用Html文档,当然也可以使用Html片断。注意:纯HTML不支持共享变量!

- - - - - - - - - - - - -
C#共享数据:学生表
编号姓名年龄
-
- - -``` -## 使用 JavaScript -+ 简单使用 -```C# -console.log("输出js日志"); -``` -+ 操作html -```C# -//改变上面html中h2文本颜色:执行后上面看效果 -document.getElementById("MyTitle").style.color = "red"; -``` -+ 使用C#共享数据,填充数据表格 -```C# -#!set --value @csharp:SharedStudents --name SharedStudentsInJs - -// 获取表格的tbody部分 -const tableBody = document.querySelector('#student tbody'); - -// 遍历数据数组 -SharedStudentsInJs.forEach(item => { - // 创建一行 - const row = document.createElement('tr'); - - // 创建单元格并填入数据 - const nameCell = document.createElement('td'); - nameCell.textContent = item.Id; - row.appendChild(nameCell); - - const ageCell = document.createElement('td'); - ageCell.textContent = item.Name; - row.appendChild(ageCell); - - const jobCell = document.createElement('td'); - jobCell.textContent = item.Age; - row.appendChild(jobCell); - - // 将该行添加到表格的tbody中 - tableBody.appendChild(row); -}); -``` -## HTTP Request -## 基本请求 -```C# -### 请求 京东 -get https://www.jd.com - -### 请求QQ -get https://www.qq.com -``` - -+ 高级请求(使用变量等) -```C# -@host=https://www.qq.com - -get {{host}} -``` -## 使用 mermaind -```C# -stateDiagram-v2 - [*] --> Active - - state Active { - [*] --> NumLockOff - NumLockOff --> NumLockOn : EvNumLockPressed - NumLockOn --> NumLockOff : EvNumLockPressed - -- - [*] --> CapsLockOff - CapsLockOff --> CapsLockOn : EvCapsLockPressed - CapsLockOn --> CapsLockOff : EvCapsLockPressed - -- - [*] --> ScrollLockOff - ScrollLockOff --> ScrollLockOn : EvScrollLockPressed - ScrollLockOn --> ScrollLockOff : EvScrollLockPressed - } - -``` -```C# -stateDiagram-v2 -state fork_state <> - [*] --> fork_state - fork_state --> State2 - fork_state --> State3 - - state join_state <> - State2 --> join_state - State3 --> join_state - join_state --> State4 - State4 --> [*] -``` diff --git a/Docs/多语言笔记.2.1.操作数据库-SQL内核.md b/Docs/多语言笔记.2.1.操作数据库-SQL内核.md deleted file mode 100644 index 00388d2..0000000 --- a/Docs/多语言笔记.2.1.操作数据库-SQL内核.md +++ /dev/null @@ -1,458 +0,0 @@ -操作数据库 -========= -原理:使用#!connect命令,连接子内核进行操作。可以连接MSSQL、SQLite、PostgreSQL等; -## 初始化 -运行各单元格之前,必须先执行一次。 -```csharp -//全局初始化 -#!import "./Base.ipynb" - -#r "nuget:Microsoft.Identity.Client,4.66.2" - -//共享 -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -``` -## 连接数据库(SQL Server 2019为例) -### 第一步:C#内核单元格中,引入相关的 nuget 包 -每种数据库都有自己的包,形如 Microsoft.DotNet.Interactive.DbName, SQL Server的包为 Microsoft.DotNet.Interactive.SqlServer -+ 在 `VS Code 终端的 NuGet 包管理` 里输入 `Microsoft.DotNet.Interactive.` 查询(把预览给勾上) -![image](./assets/images/NuGet1.jpg) - -+ 在[NuGet官网](https://www.nuget.org/)搜索 `Microsoft.DotNet.Interactive.` -![image](./assets/images/NuGet2.jpg) -```csharp -//引入 SqlServer 的 NuGet 包 -#r "nuget:Microsoft.DotNet.Interactive.SqlServer,*-*" -``` -### 第二步:使用 #!connect 命令的语法,连接数据库子内核 -使用魔术命令 `#!connect mssql --kernel-name SqlServerKernelDemo "Server=.\SQL2019;Database=study;User Id=sa;Password=gly-bicijinlian;TrustServerCertificate=true;"` - -实测有缺点: -+ 不能重复执行:重复执行会报错 -+ 连接字符串必须是真实字符串:不能是变量,不灵活;明文"不安全",比如演示环境 - -变通用法:在C#程序中,拼接好魔术命令`#!connect`,再发送给内核执行 -```csharp -// 连接魔术命令: -// #!connect mssql --kernel-name SqlServerKernelDemo "Server=.\SQL2019;Database=study;User Id=sa;Password=密码;TrustServerCertificate=true;" - -//优化用法 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SqlServerKernelDemo"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect mssql --kernel-name {magicCommandKernelName} \"{SharedDbConnect.MsSqlConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -## 查询数据库(SQL Server 2019为例) -使用SQL语法,进行数据库操作 -```sql-SqlServerKernelDemo ---语句选择 #!connect 命令设置的SQL内核名 -#!sql-SqlServerKernelDemo - ---原始SQL查询语句 -select top 10 * from student -``` -使用SQL语法,进行数据库操作 -```sql-SqlServerKernelDemo ---右下方:选择的SQL内核 - ---原始SQL查询语句 -select top 10 * from student -``` -## 连接数据库:使用 `--create-dbcontext` 参数,自动创建 EFCore 上下文 `DbContext` -说明:目前默认情况下,Microsoft.DotNet.Interactive.SqlServer里引用的Microsoft.Identity.Client包,与环境中不一样,故需要单独引用特定版本的Microsoft.Identity.Client包,不知道后续官方是否会改正。目前单独包引用放在初始化单元格。 -### 带 `--create-dbcontext` 参数的连接 -```csharp -/* 连接魔术命令 - 给 #!connect mssql 加 --create-dbcontext 参数:连接操作,会执行下面的任务: - 1、搭建EFCore基架,并初始化 DBContext 的实例: xxxx - 2、安装包相关Nuget包,详情见输出 - 3、添加新的子内核 #!sql-xxx -**/ - -//注意:由于引用的Microsoft.Identity.Client包,版本冲突,目前把 Microsoft.Identity.Client的引用,放在 Microsoft.DotNet.Interactive.SqlServer之前 -// #r "nuget:Microsoft.Identity.Client,4.66.2" 放入初始化 - -//优化用法 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SqlServerKernelWithEF"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect mssql --kernel-name {magicCommandKernelName} \"{SharedDbConnect.MsSqlConnectionString}\" --create-dbcontext"; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -### SQL内核中使用(与一般连接一样使用) -```sql-SqlServerKernelWithEF ---原始SQL查询语句 -select top 5 * from student -``` -### C#语句中,直接使用 DbContext 上下文 -```csharp -//连接建立后,执行环境中就有了相关的类:DBContext等 -/* 因为类型版本问题,不能实际执行;后续看 -{ - //直接查询 - var t = SqlServerKernelWithEF.Students.Take(5).ToList(); - display(t); - - //EF内执行SQL语句 - FormattableString fs = $"select top 3 * from Student;"; - var c = SqlServerKernelWithEF.Database.ExecuteSql(fs); - display(c); -} -*/ -``` -## 共享数据库操作结果数据(仅支持SQL Server数据库,以SQL Server 2019为例) -### 1、引入NuGet包(引入一次就好,为明确步骤再次引入) -```csharp -#r "nuget:Microsoft.DotNet.Interactive.SqlServer,*-*" -``` -### 2、连接内核命令:生成新SQL内核 -```csharp -//优化变通方式 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SqlServerKernelShared"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect mssql --kernel-name {magicCommandKernelName} \"{SharedDbConnect.MsSqlConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -### 3、共享方式使用第2步生成的新SQL内核,操作数据库(使用了 --name 命令参数) -```sql-SqlServerKernelShared -#!sql-SqlServerKernelShared --name sqlServerKernelQueryShared - -SELECT top 5 Id,Name,Age from Student; -SELECT 5 as Count; -``` -### 4、多种方式使用查询共享数据 -```csharp -//C#语言中使用:查询共享数据 - -#!set --name fromMsSqlQueryShared --value @sql-SqlServerKernelShared:sqlServerKernelQueryShared -using Microsoft.DotNet.Interactive.Formatting.TabularData; -using Microsoft.DotNet.Interactive.Formatting; -/** - 说明:这里获取到的共享SQL结果,实质是SQL操作结果的Json序列化字符串; - 在C#单元格里,默认被反序列化为了 System.Text.Json.JsonElement,其根元素RootElement,是结果集合(几条SQL语句,结果集就有几项) - .dot interactive程序集中,序列化时,实际是使用 System.Text.Json 序列化的 TabularDataResource 类(在Microsoft.DotNet.Interactive.Formatting.TabularData命名空间)的集合 - - 所以C#中使用共享数据,有两种方式:直接操作System.Text.Json.JsonElement对象和反序列化为TabularDataResource数组 -*/ -//使用共享数据:直接操作JsonElement对象 -{ - //有几个操作结果,fromMsSqlQuery.RootElement中就有几个结果集 - var dataSet = fromMsSqlQueryShared.RootElement; - - //第一个查询结果集 - var dataTable1 = dataSet[0]; - - //列结构 - var fieldNames = dataTable1.GetProperty("schema").GetProperty("fields").EnumerateArray().Select(s=>s.GetProperty("name")); - - Console.WriteLine(string.Join(" ",fieldNames)); - - //数据 - var data = dataTable1.GetProperty("data").EnumerateArray().AsEnumerable(); - foreach(var row in data) - { - Console.WriteLine($"{row.GetProperty("Id")} {row.GetProperty("Name")} {row.GetProperty("Age")}"); - } - - //第2个结果集 - var count = fromMsSqlQueryShared.RootElement[1].GetProperty("data")[0].GetProperty("Count"); - - //优化:使用Html展示 -} - -//使用共享数据:反序列化为TabularDataResource数组 -{ - var dataSetJsonText = fromMsSqlQueryShared.RootElement.GetRawText(); - var dataTables = System.Text.Json.JsonSerializer.Deserialize>(dataSetJsonText); - - //结果1 - dataTables[0].Display(); - - //结果2 - dataTables[1].Display(); -} - -//使用共享数据:直接转换为TabularDataResource数组 -{ - var resource = fromMsSqlQueryShared.RootElement.ToTabularDataResource().Data.ToList(); - resource[0].First(s => s.Key=="data").Value.Display(); -} -``` -```javascript -//js中使用:查询共享数据 -#!set --name fromMsSqlQueryShared --value @sql-SqlServerKernelShared:sqlServerKernelQueryShared -console.log(fromMsSqlQueryShared[0].data) -``` -## 各数据库示例 -### SQL Server 数据库 -```csharp -#r "nuget:Microsoft.DotNet.Interactive.SqlServer,*-*" -``` -```csharp -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; - -//优化方式 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SqlServerKernelStudy"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect mssql --kernel-name {magicCommandKernelName} \"{SharedDbConnect.MsSqlConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -```sql-SqlServerKernelStudy ---直接执行SQL语句,不共享结果 -#!sql-SqlServerKernelStudy -SELECT top 5 * from Student; -``` -```sql-SqlServerKernelStudy ---共享操作结果(可多个操作语句) -#!sql-SqlServerKernelStudy --name sqlServerQuerySharedDemo -SELECT top 5 Id,Name,Age from Student; -SELECT 5 as Count; -``` -```csharp -#!set --name fromMsSqlQuery --value @sql-SqlServerKernelStudy:sqlServerQuerySharedDemo -using Microsoft.DotNet.Interactive.Formatting.TabularData; -using Microsoft.DotNet.Interactive.Formatting; -/** - 说明:这里获取到的共享SQL结果,实质是SQL操作结果的Json序列化字符串; - 在C#单元格里,默认被反序列化为了 System.Text.Json.JsonElement,其根元素RootElement,是结果集合(几条SQL语句,结果集就有几项) - .dot interactive程序集中,序列化时,实际是使用 System.Text.Json 序列化的 TabularDataResource 类(在Microsoft.DotNet.Interactive.Formatting.TabularData命名空间)的集合 - - 所以C#中使用共享数据,有两种方式:直接操作System.Text.Json.JsonElement对象和反序列化为TabularDataResource数组 -*/ -//使用共享数据:直接操作JsonElement对象 -{ - //有几个操作结果,fromMsSqlQuery.RootElement中就有几个结果集 - var dataSet = fromMsSqlQuery.RootElement; - - //第一个查询结果集 - var dataTable1 = dataSet[0]; - - //列结构 - var fieldNames = dataTable1.GetProperty("schema").GetProperty("fields").EnumerateArray().Select(s=>s.GetProperty("name")); - - Console.WriteLine(string.Join(" ",fieldNames)); - - //数据 - var data = dataTable1.GetProperty("data").EnumerateArray().AsEnumerable(); - foreach(var row in data) - { - Console.WriteLine($"{row.GetProperty("Id")} {row.GetProperty("Name")} {row.GetProperty("Age")}"); - } - - //第2个结果集 - var count = fromMsSqlQuery.RootElement[1].GetProperty("data")[0].GetProperty("Count"); - - //优化:使用Html展示 -} - -//使用共享数据:反序列化为TabularDataResource数组 -{ - var dataSetJsonText = fromMsSqlQuery.RootElement.GetRawText(); - var dataTables = System.Text.Json.JsonSerializer.Deserialize>(dataSetJsonText); - - //结果1 - dataTables[0].Display(); - - //结果2 - dataTables[1].Display(); -} - -//使用共享数据:直接转换为TabularDataResource数组 -{ - var resource = fromMsSqlQuery.RootElement.ToTabularDataResource().Data.ToList(); - resource[0].First(s => s.Key=="data").Value.Display(); -} -``` -```javascript -#!set --name fromMsSqlQuery --value @sql-SqlServerKernelStudy:sqlServerQuerySharedDemo -console.log(fromMsSqlQuery[0].data) -``` -### PostgreSQL 数据库 -```csharp -#r "nuget:Microsoft.DotNet.Interactive.PostgreSQL,*-*" -``` -```csharp -//魔术命令 -//#!connect postgres --kernel-name PostgreSQLStudy "Host=localhost;Port=5432;Username=postgres;Password=替换成真实密码;Database=Study;" - -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; - -//优化方法 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "PostgreSQLStudy"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect postgres --kernel-name {magicCommandKernelName} \"{SharedDbConnect.PSQLConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -```sql-PostgreSQLStudy -#!sql-PostgreSQLStudy -SELECT * FROM "Student" LIMIT 2; -SELECT COUNT(*) as Count FROM "Student"; -``` -### SQLite 数据库 -```csharp -#r "nuget:Microsoft.DotNet.Interactive.SQLite,*-*" -``` -```csharp - -/* 各种连接参数 - - 相对位置:当前目录 - #!connect sqlite --kernel-name SQLiteSharedKernel --connection-string "Data Source=.\assets\database\study.db;" - - 绝对目录位置 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=C:\Database\study.db;" - - 缓存共享 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=.\assets\database\study.db;Cache=Shared;" - - 使用带密码 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=.\assets\database\study.db;Cache=Shared;Password=MyEncryptionKey;" - - 只读模式 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=.\assets\database\study.db;Mode=ReadOnly" - - 读写创建模式 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=.\assets\database\study.db;Mode=ReadWriteCreate" - - 读写模式 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=.\assets\database\study.db;Mode=ReadWrite" - - 私有内存模式 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=:memory:" - - 共享内存模式 - #!connect sqlite --kernel-name MySQLiteDemo "Data Source=Sharable;Mode=Memory;Cache=Shared" -*/ - -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -//优化方法 -{ - //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用 - string magicCommandKernelName = "SQLiteSharedKernel"; - string completeKernelName = "sql-" + magicCommandKernelName; - - //引入内核:可重复执行 - if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null) - { - var connectKernelCode = $"#!connect sqlite --kernel-name {magicCommandKernelName} --connection-string \"{SharedDbConnect.SQLiteConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - } - else - { - Console.WriteLine($"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -```sql-SQLiteSharedKernel -#!sql-SQLiteSharedKernel -SELECT * FROM Student LIMIT 2; -SELECT COUNT(*) AS Count FROM Student; -``` -### DuckDB 数据库 -```csharp -#r "nuget:Microsoft.DotNet.Interactive.DuckDB,*-*" -``` -```csharp -//下面这种被注释的方式:不可重复执行 -// #!connect duckdb --kernel-name DuckDBSharedKernel --connection-string "Data Source=:memory:?cache=shared" -// #!connect duckdb --kernel-name DuckDBSharedKernel --connection-string SharedDbConnect.DuckDBConnectionString - -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -//优化方法 -{ - //内核名:魔法命令中的内核名,执行后会不加 sql- 前缀 - string magicCommandKernelName = "DuckDBSharedKernel"; - - //引入内核:可重复执行 - if(Kernel.Root.FindKernelByName(magicCommandKernelName) == null) - { - var connectKernelCode = $"#!connect duckdb --kernel-name {magicCommandKernelName} --connection-string \"{SharedDbConnect.DuckDBConnectionString}\""; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, "csharp")); - - //初始化数据表及填充数据 - var connectKernelCode2 = - """ - #!DuckDBSharedKernel - CREATE TABLE Student ( - Id INTEGER, - Name TEXT, - Age INTEGER - ); - INSERT INTO Student VALUES (1, '张三', 10), (2, '李四', 33), (3, '王五', 66); - """; - await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode2, "csharp")); - } - else - { - Console.WriteLine($"名为 {magicCommandKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!"); - } -} -``` -```DuckDBSharedKernel -#!DuckDBSharedKernel -SELECT * FROM Student ORDER BY Id -``` diff --git a/Docs/多语言笔记.5.1.使用扩展库.md b/Docs/多语言笔记.5.1.使用扩展库.md deleted file mode 100644 index e989023..0000000 --- a/Docs/多语言笔记.5.1.使用扩展库.md +++ /dev/null @@ -1,112 +0,0 @@ -# 使用 扩展库 Microsoft.DotNet.Interactive.ExtensionLab -Microsoft.DotNet.Interactive.ExtensionLab 是 .NET Interactive 的扩展工具库,主要用于增强交互式编程环境的功能性,提供实验性功能模块和高级数据处理能力。 -## 初始化 -```csharp -#!import "./Base.ipynb" -``` -## 添加 Nuget 包 -添加包成功后,有用法摘要提示! -```csharp -//添加 Nuget 包 -#r "nuget:Microsoft.DotNet.Interactive.ExtensionLab,*-*" -#r "nuget:Microsoft.Data.Analysis" - -using Microsoft.DotNet.Interactive; -using Microsoft.DotNet.Interactive.Commands; -using Microsoft.DotNet.Interactive.Documents; -using Microsoft.DotNet.Interactive.Utility; - -using Microsoft.DotNet.Interactive.ExtensionLab; -using Microsoft.Data.Analysis; -``` -## 使用 #!linqify 魔法命令 -`#!linqify` 魔法命令, 将一个普通的(通常是 C#)代码块转换为 LINQ 查询表达式。这允许你使用更简洁、更声明式的 LINQ 语法来操作数据集合。 - -注意:没有提供新的Linq功能,只是对原生linq的增强(隐匿返回),方便在Polyglot Notebooks 中使用而已。使用原生还是增强的,随个人喜好。 - -增强: -+ 隐式返回 - 在普通的 C# 代码中,你需要显式地 return LINQ 查询的结果才能看到输出。 使用 #!linqify,查询结果会自动作为单元格的输出返回,无需显式 return 语句。这在交互式 notebook 环境中更方便。 - -+ 简洁性 - #!linqify 允许你省略一些样板代码。例如,你不需要定义一个单独的变量来存储 LINQ 查询的结果。 - -+ 交互性 - #!linqify是为了更好地适应交互式 notebook 环境而设计的。它简化了在 notebook 中快速编写、执行和查看 LINQ 查询结果的过程。 -`C#原生Linq` 与 `linqify魔法命令` 使用对比 -```csharp -//公用数据 -var students = new List() -{ - new Student(){Id = 1, Name = "张三", Age = 8}, - new Student(){Id = 2, Name = "李四", Age = 95}, - new Student(){Id = 3, Name = "王五", Age = 60}, - new Student(){Id = 4, Name = "张三丰", Age = 54}, - new Student(){Id = 5, Name = "王二小", Age = 21}, - new Student(){Id = 6, Name = "刘胡兰", Age = 74}, - new Student(){Id = 7, Name = "列宁", Age = 19}, - new Student(){Id = 8, Name = "江姐", Age = 52}, - new Student(){Id = 9, Name = "张海迪", Age = 33}, - new Student(){Id = 10, Name = "周小呼", Age = 46}, -}; -``` -```csharp -//原生Linq -var result = students.Where(s => s.Name.StartsWith("张")).ToList(); -result.Display(); - -//或者 -var result2 = from s in students - where s.Name.StartsWith("张") - select s; -result.Display(); -``` -```csharp -#!linqify -students.Where(it => it.Age > 20) -``` -总结: - -+ #!linqify 不是为了实现 LINQ 本身。 -+ #!linqify 是为了简化 LINQ 在 .NET Interactive Notebooks 中的 交互式使用,通过提供隐式返回和更简洁的语法。 -+ 在功能上,使用 #!linqify 和直接编写 C# LINQ 代码是等价的。 你可以选择哪种方式更适合你的编码风格和工作流程。 -## ExplainCode -这个扩展使用 Mermaid 内核为 csharp 代码生成序列图.以直观的图形方式,展现代码的执行流程。 -```csharp -#!explain - -var data = new[] { 1, 2, 3 }; -for (var i = 0; i < data.Length; i++) -{ - Console.WriteLine(i.ToString()); -} -``` -```csharp -#!explain - -"Hello Explain".Display(); -``` -## 使用 #!inspect 命令,检查代码编译详细信息! -#!inspect 命令,允许您查看C#单元格代码的反编译、IL和JIT Asm. 注意:深色模式下,展示区顶部的Tab[C# | IL JIT | ASM]不明显,但可以正常点击切换,或者换个VSCode主题。 -```csharp -#!inspect -foreach(var x in Enumerable.Range(1,10)) -{ - Console.WriteLine(x); -} -``` -## 使用 #!record命令来保存您运行的代码的副本 -一旦您使用 #!recore 启用转录本记录,每个代码提交(包括重新运行的单元格)都记录在指定的文件中。所使用的JSON格式与.NET Interactive stdio和http API识别的格式相同,可用于通过自动化回放交互式会话。 -1. 使用 record 魔法命令,设定转录文件 -```csharp -#!record --output recore.json -//会在笔记所在的目录生成 recore.json 文件 - -Console.WriteLine("hello,record!"); -``` -2. 读取转录文件 -```csharp -using System.IO; -var fileContent = await File.ReadAllTextAsync("recore.json",System.Text.Encoding.UTF8); -Console.WriteLine(fileContent); -``` diff --git a/Docs/多语言笔记.6.1.共享变量.md b/Docs/多语言笔记.6.1.共享变量.md deleted file mode 100644 index d4fa383..0000000 --- a/Docs/多语言笔记.6.1.共享变量.md +++ /dev/null @@ -1,209 +0,0 @@ -在笔记中共享数据(变量) -==================== -使用 .NET 交互式内核,可以在单个笔记本中以多种语言编写代码。为了利用每种语言的不同优势,您会发现在它们之间共享数据很有用。即一种语言的变量,可以在其它语言中使用。 -默认情况下,.NET Interactive 支持多种不同的语言,其中大多数语言都允许使用magic 命令`#!set` 和 `#!shared` 进行共享。 -## 变量共享的语言支持情况 -| 语言 | 变量共享 | -| ---- | ---- | -| C# | 支持 | -| F# | 支持 | -| PowerShell | 支持 | -| JavaScript | 支持 | -| SQL | 支持 | -| KQL | 支持 | -| Python | 支持 | -| R | 支持 | -| HTML | 不支持 | -| Mermaid | 不支持 | -## 同种内核 默认共享数据 -同种内核的不同单元格之间,无需任何操作,变量默认共享,后续单元格直接使用前面已执行单元格的数据。 -+ JS 各单元格共享示例: -```javascript -//声明变量 -JsShared = "jsShared"; -``` -```javascript -//直接使用上面单元格变量 -console.log(JsShared); -``` -+ C# 各单元格共享示例: -```csharp -//声明变量 -string CsharpShared = "CsharpShared"; -``` -```csharp -//直接使用 -Console.WriteLine(CsharpShared); -``` -## 使用 `#!set` 和 `#!shared` 魔法命令共享数据 -> `#!shared` 魔法命令从 .NET Interactive 的早期就已经存在,而 `#!set` 是较新的命令,它提供了` #!share` 功能的超集。由于 `#!set` 具有更丰富的功能并且更具可读性,因此就优先使用`#!set`。 -> 把 `#!share` 命令重写为 `#!set` 命令很容易 -`#!share` 用法的示例: -```javascript -//声明一个要被共享的js变量 - -//共享的变量声明不要加var、let、const关键字,加了变局部变量 -jsVar = "js变量值"; - - -#!share --from javascript jsVar --as csVarFromJs22222 - -``` -```csharp -//共享变量 - -#!share --from javascript jsVar --as csVarFromJs -Console.WriteLine(csVarFromJs); -``` -改写为 等价的 `#!set` 命令: -```csharp -#!set --name csVarFromJs --value @javascript:jsVar -Console.WriteLine(csVarFromJs); -``` -`#!share`命令通过 --from 选项,声明了共享数据来源,通过 --as 选项 声明共享变量的新名称,方便后续使用; -`#!set`命令通过更加明确的选项 `--name` 和 `--value` 选项, 指明了共享数据的值(形如:@来源:值形)和新名称; -## 变量视图:管理变量 -![变量共享](./assets/images/shared.001.jpg) -## 内核之间共享数据 -示例:C# 运行中的变量,被其它语言共享。 -```csharp -//定义变量:存储网关 -string getway = "192.168.1.1"; -``` -+ PowerShell 中使用 -```pwsh -# Poweshell中使用 前面C#单元中定义的变量 -# 特别注意:因为PS中变量名必须以$开头,所以在命令中 name 参数名,在PS中使用时必须加$前辍 - -#!set --value @csharp:getway --name gw - -Write-Host $gw -``` -+ F# 中使用 -```fsharp -#!set --value @csharp:getway --name getway - -Console.WriteLine(getway) -``` -+ 在javascrip中使用 -```javascript -#!set --value @csharp:getway --name getway -console.log(getway); -``` -## 从用户输入中设置变量 -共享数据变量的值,不但能直接设置、来自其它变量,还可以是由用户输入的。这在需要用户交互时,非常有用,比如:需要用户输入密码、流程控制由用户选择等。 - -注意:执行后,会在VS Code顶部,弹出一个小的用户输入窗口,用户输入内容并且确认后,用户的输入内容会被存储为变量的值. -可以在魔法命令中使用一个@input前缀,直接从用户输入中设置一个值。比如: -```csharp -#!set --name userName --value @input("请输入姓名"); -Console.WriteLine($"输入的姓名是:{userName}") -``` -如果希望用户输入在UI中被遮盖(比如不希望在屏幕上显示的秘密),可以使用@password前缀来代替@input -```csharp -#!set --name userPassword --value @password("请输入密码"); -Console.WriteLine($"输入的密码是:{userPassword}"); -``` -通过和前缀请求用户输入的能力不仅仅局限于共享数据的魔法命令,还可以在程序中使用。比如: -```csharp -using Microsoft.DotNet.Interactive; - -var input = await Kernel.GetInputAsync("Pick a number."); -Console.WriteLine($"输入为:{input}") -``` -## MIME 类型 -在.NET Interactive中,当变量在子内核之间共享时,通常需要将其转换为某种字符串表示形式。这是因为.NET Interactive中的许多子内核运行在不同的进程中。例如,核心内核在其自己的.NET进程中运行,而多语言笔记本扩展在VS Code进程中运行。你还可以在远程机器上运行子内核。子内核也可以在不同的平台上实现,例如.NET和JavaScript。 - -因此,虽然在共享进程时,.NET语言之间可以通过引用共享变量,但共享的主要用例涉及某种形式的序列化。序列化格式由MIME类型指定,用户可以通过可选的选项来指定。如果不指定选项,则默认使用text/plain MIME类型用于变量共享。 - -这意味着请求的变量将由源内核序列化为JSON,然后可选地由目标内核进行反序列化。对于基于.NET的内核,序列化使用特定的方法进行。在基于.NET的目标内核中使用的反序列化策略如下: - -| 源json类型 | 目标.NET类型 | -| ---- | ---- | -| boolean | System.Boolean | -| number | System.Double | -| string | System.String | -| other | System.Text.Json.JsonDocument | - -将变量转换为指定的MIME类型是通过使用.NET Interactive格式化API完成的,这些API可以定制。 -## 引用共享 -默认情况下的共享是值共享(即副本共享),在特定情况下,引用类型变量可以通过引用进行共享。但要注意: -+ 源和目标内核必须在同一进程中运行。 -+ 源和目标内核必须基于公共语言运行时(如C#、F#、PowerShell)。 -+ 如果使用的是#!set--byref,引用共享仅在使用该选项时启用。 -+ 如果使用的是#!share--mime-type,引用共享是默认行为,但在使用该选项时会禁用。 - -因此,如果共享一个可变对象,其状态的更改将在子内核间立即可见,这与默认的基于序列化的共享不同。 -```fsharp -//F# 声明数组 -open System.Collections.Generic; -let messages = List() -messages.Add "由F#添加" -``` -```csharp -//C#获取并修改 -#!set --byref --value @fsharp:messages --name msgList - -msgList.Add("由C#添加"); -msgList.Display(); - -``` -```fsharp -//F#中的原数组,已被C#修改 -messages -``` -## `#!value` 内核,直接设置值 -在笔记本中使用文本是很常见的需求。这些文本可能是JSON、CSV、XML或其他格式。它们可能存在于文件中、剪贴板上,或者在网页上。 - -为了尽可能方便地将这些文本导入到笔记本中的变量里,我们提供了`#!value`魔法命令。需要知道的重要一点是,这是一个别名,指向一个专门设计用于存储值的子内核。这意味着一旦将某些内容存储在其中,就可以通过或从另一个子内核访问它(`#!set` `#!share`) - -有三种方法可以使用来将数据导入到你的笔记本会话中: -+ 剪贴板 - -最简单的使用方法是将一些文本粘贴到单元格中。文本将被存储为字符串,但与在C#、F#或PowerShell中使用字面量不同,这里不需要转义任何内容。 -```value -#!value --name StudentJson -{ - "Id":2, - "Name":"小李", - "Age":33 -} -``` -```csharp -#!set --name fromValueKernel --value @value:StudentJson - -fromValueKernel.Display(); -``` -+ 文件 -数据存储在一个文件中时,使用带有选项的命令:#!value--from-file, 获取共享数据。 -```value -#!value --name fromFileData --from-file ./shared/file/data.json -``` -```csharp -#!set --name fromValueFileData --value @value:fromFileData - -fromValueFileData.Display(); -``` -+ URL -也可以使用--from-url选项,从一个URL地址获取数据 -```value -#!value --name fromUrlData --from-url https://www.qq.com -``` -```csharp -#!set --name fromValueUrlData --value @value:fromUrlData - -fromValueUrlData.Display(); -``` -## 指定 MIME 类型 -无论使用哪种方法,都可以使用`--mime-type`选项在提交时选择在笔记本中显示值。如果笔记本前端知道如何显示mime类型,可以看到它格式正确: -```value -#!value --name JsonData --mime-type application/json -{ - "Id":2, - "Name":"小张", - "Adress":{ - "Code":"0394", - "info":"变法路36号101" - } -} -``` diff --git a/Docs/多语言笔记.7.1.运行xUnit单元测试.md b/Docs/多语言笔记.7.1.运行xUnit单元测试.md deleted file mode 100644 index 6e3b6d7..0000000 --- a/Docs/多语言笔记.7.1.运行xUnit单元测试.md +++ /dev/null @@ -1,106 +0,0 @@ -运行 xUnit 单元测试 -===================== -Polgylot Notebooks 并没有直接支持单元测试框架。不能像VS里那样方便的进行单元测试。简单远行的话,可以使用下面的方案! -## 1、引入必要的NuGet包到.NET Interactive环境中 -```csharp -// 默认包源 -#i "nuget:https://api.nuget.org/v3/index.json" - -//Nuget 包引用 -#r "nuget:xunit" -#r "nuget: xunit.assert" -#r "nuget:xunit.runner.visualstudio" -#r "nuget:xunit.runner.console" -``` -## 2、定义测试类和测试方法 -```csharp -using Xunit; - -public class CalculatorTests -{ - [Fact] - public void Add_ReturnsCorrectSum() - { - var calculator = new Calculator(); - var result = calculator.Add(2, 2); - Assert.Equal(4, result); - } - - [Fact] - public void Subtract_ReturnsCorrectDifference() - { - var calculator = new Calculator(); - var result = calculator.Subtract(5, 3); - Assert.Equal(2, result); - } -} - -public class Calculator -{ - public int Add(int x, int y) => x + y; - public int Subtract(int x, int y) => x - y; -} - -``` -## 3、执行测试并获取结果。在.NET Interactive中,直接运行xUnit测试并不像在Visual Studio或通过命令行那样直接。你需要手动实例化测试类并调用测试方法,或者使用反射来自动发现和执行测试方法。以下是一个简化的例子,展示如何手动执行测试方法并输出结果。 -+ 手动调用测试 -```csharp -// 手动执行测试方法 -var calculatorTests = new CalculatorTests(); - -// 执行Add_ReturnsCorrectSum测试 -calculatorTests.Add_ReturnsCorrectSum(); - -// 执行Subtract_ReturnsCorrectDifference测试 -calculatorTests.Subtract_ReturnsCorrectDifference(); - -Console.WriteLine("Tests executed successfully."); - -``` -+ 使用反射的例子 -```csharp -#r "nuget: xunit" -#r "nuget: xunit.assert" - -using Xunit; -using System.Reflection; - -``` -```csharp -//被测试类 -public class Calculator -{ - public int Add(int a, int b) => a + b; -} - -//测试类 -public class CalculatorTests -{ - [Fact] - public void Add_TwoNumbers_ReturnsSum() - { - var calculator = new Calculator(); - int result = calculator.Add(1, 2); - Assert.Equal(3, result); //:ml-citation{ref="3,4" data="citationList"} - } -} - -//使用反射,调用被测试类 -var testInstance = new CalculatorTests(); -var testMethods = testInstance.GetType() - .GetMethods() - .Where(m => m.GetCustomAttributes(typeof(FactAttribute), false).Length > 0); - -foreach (var method in testMethods) -{ - try - { - method.Invoke(testInstance, null); - Console.WriteLine($"✅ {method.Name} 通过"); - } - catch (Exception ex) - { - Console.WriteLine($"❌ {method.Name} 失败: {ex.InnerException?.Message}"); - } -} -```