多语言笔记系列:共享数据
在笔记中共享数据(变量)
使用 .NET 交互式内核,可以在单个笔记本中以多种语言编写代码。为了利用每种语言的不同优势,您会发现在它们之间共享数据很有用。即一种语言的变量,可以在其它语言中使用。
默认情况下,.NET Interactive 支持多种不同的语言,其中大多数语言都允许使用magic 命令#!set
和 #!shared
进行共享。
变量共享的语言支持情况
语言 | 变量共享 |
---|---|
C# | 支持 |
F# | 支持 |
PowerShell | 支持 |
JavaScript | 支持 |
SQL | 支持 |
KQL | 支持 |
Python | 支持 |
R | 支持 |
HTML | 不支持 |
Mermaid | 不支持 |
同种内核 默认共享数据
同种内核的不同单元格之间,无需任何操作,变量默认共享,后续单元格直接使用前面已执行单元格的数据。
- JS 各单元格共享示例:
//声明变量
JsShared = "jsShared";
//直接使用上面单元格变量
console.log(JsShared);
- C# 各单元格共享示例:
//声明变量
string CsharpShared = "CsharpShared";
//直接使用
Console.WriteLine(CsharpShared);
使用 #!set
和 #!shared
魔法命令共享数据
#!shared
魔法命令从 .NET Interactive 的早期就已经存在,而#!set
是较新的命令,它提供了#!share
功能的超集。由于#!set
具有更丰富的功能并且更具可读性,因此就优先使用#!set
。
把#!share
命令重写为#!set
命令很容易
#!share
用法的示例:
//声明一个要被共享的js变量//共享的变量声明不要加var、let、const关键字,加了变局部变量
jsVar = "js变量值";#!share --from javascript jsVar --as csVarFromJs22222
//共享变量#!share --from javascript jsVar --as csVarFromJs
Console.WriteLine(csVarFromJs);
改写为 等价的 #!set
命令:
#!set --name csVarFromJs --value @javascript:jsVar
Console.WriteLine(csVarFromJs);
#!share
命令通过 --from 选项,声明了共享数据来源,通过 --as 选项 声明共享变量的新名称,方便后续使用;
#!set
命令通过更加明确的选项 --name
和 --value
选项, 指明了共享数据的值(形如:@来源:值形)和新名称;
变量视图:管理变量
内核之间共享数据
示例:C# 运行中的变量,被其它语言共享。
//定义变量:存储网关
string getway = "192.168.1.1";
- PowerShell 中使用
# Poweshell中使用 前面C#单元中定义的变量
# 特别注意:因为PS中变量名必须以$开头,所以在命令中 name 参数名,在PS中使用时必须加$前辍#!set --value @csharp:getway --name gwWrite-Host $gw
- F# 中使用
#!set --value @csharp:getway --name getwayConsole.WriteLine(getway)
- 在javascrip中使用
#!set --value @csharp:getway --name getway
console.log(getway);
从用户输入中设置变量
共享数据变量的值,不但能直接设置、来自其它变量,还可以是由用户输入的。这在需要用户交互时,非常有用,比如:需要用户输入密码、流程控制由用户选择等。
注意:执行后,会在VS Code顶部,弹出一个小的用户输入窗口,用户输入内容并且确认后,用户的输入内容会被存储为变量的值.
可以在魔法命令中使用一个@input前缀,直接从用户输入中设置一个值。比如:
#!set --name userName --value @input("请输入姓名");
Console.WriteLine($"输入的姓名是:{userName}")
如果希望用户输入在UI中被遮盖(比如不希望在屏幕上显示的秘密),可以使用@password前缀来代替@input
#!set --name userPassword --value @password("请输入密码");
Console.WriteLine($"输入的密码是:{userPassword}");
通过和前缀请求用户输入的能力不仅仅局限于共享数据的魔法命令,还可以在程序中使用。比如:
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,引用共享是默认行为,但在使用该选项时会禁用。
因此,如果共享一个可变对象,其状态的更改将在子内核间立即可见,这与默认的基于序列化的共享不同。
//F# 声明数组
open System.Collections.Generic;
let messages = List<string>()
messages.Add "由F#添加"
//C#获取并修改
#!set --byref --value @fsharp:messages --name msgListmsgList.Add("由C#添加");
msgList.Display();
//F#中的原数组,已被C#修改
messages
#!value
内核,直接设置值
在笔记本中使用文本是很常见的需求。这些文本可能是JSON、CSV、XML或其他格式。它们可能存在于文件中、剪贴板上,或者在网页上。
为了尽可能方便地将这些文本导入到笔记本中的变量里,我们提供了#!value
魔法命令。需要知道的重要一点是,这是一个别名,指向一个专门设计用于存储值的子内核。这意味着一旦将某些内容存储在其中,就可以通过或从另一个子内核访问它(#!set
#!share
)
有三种方法可以使用来将数据导入到你的笔记本会话中:
- 剪贴板
最简单的使用方法是将一些文本粘贴到单元格中。文本将被存储为字符串,但与在C#、F#或PowerShell中使用字面量不同,这里不需要转义任何内容。
#!value --name StudentJson
{"Id":2,"Name":"小李","Age":33
}
#!set --name fromValueKernel --value @value:StudentJsonfromValueKernel.Display();
- 文件
数据存储在一个文件中时,使用带有选项的命令:#!value–from-file, 获取共享数据。
#!value --name fromFileData --from-file ./shared/file/data.json
#!set --name fromValueFileData --value @value:fromFileDatafromValueFileData.Display();
- URL
也可以使用--from-url选项,从一个URL地址获取数据
#!value --name fromUrlData --from-url https://www.qq.com
#!set --name fromValueUrlData --value @value:fromUrlDatafromValueUrlData.Display();
指定 MIME 类型
无论使用哪种方法,都可以使用--mime-type
选项在提交时选择在笔记本中显示值。如果笔记本前端知道如何显示mime类型,可以看到它格式正确:
#!value --name JsonData --mime-type application/json
{"Id":2,"Name":"小张","Adress":{"Code":"0394","info":"变法路36号101"}
}