master
bicijinlian 2 months ago
parent 6795af27d4
commit dcd233f9d5

@ -0,0 +1,149 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "0be6f6cc",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.Configuration, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.Binder, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.CommandLine, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.EnvironmentVariables, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.ini, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.json, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.KeyPerFile, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.UserSecrets, 9.0.4</span></li><li><span>Microsoft.Extensions.Configuration.xml, 9.0.4</span></li><li><span>Microsoft.Extensions.DependencyInjection, 9.0.4</span></li><li><span>Microsoft.Extensions.Logging, 9.0.4</span></li><li><span>Microsoft.Extensions.Logging.Configuration, 9.0.4</span></li><li><span>Microsoft.Extensions.Logging.Console, 9.0.4</span></li><li><span>Microsoft.Extensions.Logging.Debug, 9.0.4</span></li><li><span>Microsoft.Extensions.Logging.EventSource, 9.0.4</span></li><li><span>Microsoft.Extensions.Options, 9.0.4</span></li><li><span>Microsoft.Extensions.Options.ConfigurationExtensions, 9.0.4</span></li><li><span>Microsoft.Extensions.Options.DataAnnotations, 9.0.4</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"ename": "Error",
"evalue": "(66,24): error CS0234: 命名空间“System.ComponentModel”中不存在类型或命名空间名“DataAnnotations”(是否缺少程序集引用?)",
"output_type": "error",
"traceback": [
"(66,24): error CS0234: 命名空间“System.ComponentModel”中不存在类型或命名空间名“DataAnnotations”(是否缺少程序集引用?)"
]
}
],
"source": [
"#r \"nuget:Microsoft.Extensions.DependencyInjection\"\n",
"#r \"nuget:Microsoft.Extensions.Options\"\n",
"#r \"nuget:Microsoft.Extensions.Options.DataAnnotations\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.Binder\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.ini\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.xml\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.json\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.KeyPerFile\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.UserSecrets\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.CommandLine\"\n",
"#r \"nuget:Microsoft.Extensions.Configuration.EnvironmentVariables\"\n",
"#r \"nuget:Microsoft.Extensions.Options.ConfigurationExtensions\"\n",
"#r \"nuget:Microsoft.Extensions.Logging\"\n",
"#r \"nuget:Microsoft.Extensions.Logging.Console\"\n",
"#r \"nuget:Microsoft.Extensions.Logging.Debug\"\n",
"#r \"nuget:Microsoft.Extensions.Logging.EventSource\"\n",
"#r \"nuget:Microsoft.Extensions.Logging.Configuration\"\n",
"\n",
"global using Microsoft.Extensions.DependencyInjection;\n",
"global using Microsoft.Extensions.Configuration;\n",
"global using Microsoft.Extensions.Configuration.Ini;\n",
"global using Microsoft.Extensions.Configuration.Xml;\n",
"global using Microsoft.Extensions.Configuration.Memory;\n",
"global using Microsoft.Extensions.Configuration.Json;\n",
"global using Microsoft.Extensions.Configuration.CommandLine;\n",
"global using Microsoft.Extensions.Configuration.EnvironmentVariables;\n",
"global using Microsoft.Extensions.Options;\n",
"global using Microsoft.Extensions.Logging;\n",
"global using Microsoft.Extensions.Logging.Debug;\n",
"global using Microsoft.Extensions.Logging.Console;\n",
"global using Microsoft.Extensions.Logging.EventSource;\n",
"global using Microsoft.Extensions.Logging.Configuration;\n",
"\n",
"//环境变量\n",
"//Environment.SetEnvironmentVariable(\"Database:PSQL\", \"Host=localhost;Port=5432;Username=postgres;Password=psql-461400;Database=Study;\", EnvironmentVariableTarget.Process);\n",
"\n",
"//配置文件\n",
"IConfigurationBuilder configBuilder = new ConfigurationBuilder();\n",
"configBuilder\n",
" .SetBasePath(Environment.CurrentDirectory)\n",
" .AddJsonFile(\"config.json\",false,true)\n",
" .AddEnvironmentVariables()\n",
" .AddUserSecrets(\"PolyglotNotebooksStudy\",true)\n",
" .AddCommandLine(new string[]{})\n",
";\n",
"\n",
"public IConfiguration DataBaseConfig = configBuilder.Build();\n",
"\n",
"//DI\n",
"ServiceCollection Services = new ServiceCollection();\n",
"Services\n",
" .AddSingleton<IConfiguration>(DataBaseConfig)\n",
" .AddLogging(setup =>\n",
" {\n",
" setup.AddConfiguration();\n",
" setup.AddDebug();\n",
" setup.AddConsole();\n",
" })\n",
" ;\n",
"public ServiceProvider SharedContainer = Services.BuildServiceProvider();\n",
"\n",
"public class DbConnectionString\n",
"{\n",
" public string MsSqlConnectionString {get;set;}\n",
" public string MySQLConnectionString {get;set;}\n",
" public string PSQLConnectionString {get;set;}\n",
" public string SQLiteConnectionString {get;set;}\n",
" public string DuckDBConnectionString {get;set;}\n",
"}\n",
"\n",
"///<summary>\n",
"/// 数据库连接字符串\n",
"///</summary>\n",
"public DbConnectionString SharedDbConnect = new DbConnectionString()\n",
"{\n",
" MsSqlConnectionString = DataBaseConfig.GetValue<string>(\"Database:SQLServer\"),\n",
" MySQLConnectionString = DataBaseConfig.GetValue<string>(\"Database:MySQL\"),\n",
" PSQLConnectionString = DataBaseConfig.GetValue<string>(\"Database:PSQL\"),\n",
" SQLiteConnectionString = DataBaseConfig.GetValue<string>(\"Database:SQLite\"),\n",
" DuckDBConnectionString = DataBaseConfig.GetValue<string>(\"Database:DuckDB\"),\n",
"};\n",
"\n",
"//SharedDbConnect.Display();\n",
"\n",
"public class Student\n",
"{\n",
" public int Id {get;set;}\n",
"\n",
" public string Name {get;set;}\n",
"\n",
" public int Age {get;set;}\n",
"}"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"languageName": "csharp",
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

@ -0,0 +1,9 @@
{
"Database":{
"SQLServer":"Server=.\\SQL2019;Database=study;User Id=sa;Password=gly-bicijinlian;TrustServerCertificate=true;",
"MySQL":"Server=localhost;Port=3306;Database=Study;Uid=sa;Pwd=mysql-461400;",
"PSQL":"Host=localhost;Port=5432;Username=postgres;Password=psql-461400;Database=Study;",
"SQLite":"Data Source=.\\assets\\database\\Study.db;",
"DuckDB":"Data Source=:memory:?cache=shared"
}
}

Binary file not shown.

File diff suppressed because one or more lines are too long

@ -0,0 +1,336 @@
单元格输出的格式化
================
## 格式化输出
基于 .NET Interactive 的工具(包括 Polyglot 笔记本、Jupyter 和其他工具)的输出是通过 .NET Interactive 格式化器生成的,这是一组位于 Microsoft.DotNet.Interactive.Formatting 命名空间下的 API。这些 API 可以作为一个 NuGet 包独立于笔记本使用。
格式化器创建对象的字符串表示,这些字符串表示可以从纯文本到 HTML再到像 JSON 和 CSV 这样的机器可读格式。
以下是一些你可以在笔记本中编写的代码示例,这些代码会导致对象被格式化以供显示:
- C# 单元格末尾的返回语句或尾随表达式
- F# 单元格末尾的尾随表达式
- 调用 Display 和 ToDisplayString 扩展方法,这些方法对 C# 和 F# 中的所有对象都可用
- 在 PowerShell 单元格中调用 Out-Display
格式化器还用于在多语言笔记本变量视图中格式化.NET对象的输出显示。其他语言的值格式化并不依赖于.NET。
> `格式化` 指的是创建对象字符串表示的过程。此过程由.NET Interactive内核通过此处所述的API实现。当格式化后的字符串在 VS Code 或 JupyterLab 中的笔记本上显示时,这一过程被称为`渲染`
## MIME类型 与 Display显示
对于任何一个给定的对象可以有多种不同的字符串表示方式。这些不同的表示方式都有对应的MIME类型这些类型由简短的字符串标识例如`text/html`或`application/json`。MIME类型可以用来通过Display扩展方法请求特定格式的对象显示这个方法可以用于任何对象。
例如我们可以调用rect.Display()来显示分配给变量rect的Rectangle对象
```csharp
//注意System.Drawing不能跨平台只在Windows系统中使用。
//不知道为啥:官方要选个不跨平台的示例
using System.Drawing;
var ract = new Rectangle
{
Height = 50,
Width = 100,
};
//默认为 text/html下面两种方式的效果是一样的
ract.Display();
ract.Display("text/html");
```
注意Polyglot 笔记本中默认的 MIME 类型是 text/html。这可能会因 .NET 类型的不同而有所变化,但在上述示例中,矩形类型尚未应用任何自定义设置。(将在下面展示更多关于如何进行自定义设置的内容。)
> 注意:对于 C# 或 F# 中单元格的返回值,只能使用默认 MIME 类型的格式化程序。
在使用Display时可以指定不同于默认的MIME类型。只需将所需的MIME类型作为参数传递即可例如rect.Display("text/plain")
```csharp
ract.Display("text/plain");
```
另一种常见的MIME类型是application/json。在Polyglot笔记本中使用此MIME类型时对象使用System.Text.Json进行格式化。
执行下面的单元格会以Json格式输出。JSON输出中的代码颜色由 VS Code 笔记本渲染器针对`application/json`类型提供。
```csharp
ract.Display("application/json");
```
## 自定义格式化
.NET Interactive的格式化API是高度可配置的。
可以使用`Microsoft.DotNet.Interactive.Formatting`中的代码,调整格式化行为的方式。
### 限制输出数量
在格式化序列时例如数组或实现IEnumerable的对象.NET Interactive的格式化器会将它们展开以便你可以看到其中的值。
如果执行结果集太多,默认情况下只会输出前面很少项,剩余的数据以 `...More` 代替。
```csharp
var names = new string[]
{
"吕宇宁", "韦子异", "姚宇宁", "傅子异", "朱子韬", "林杰宏", "胡璐", "周璐", "田秀英", "姜詩涵", "蔡秀英", "张睿", "金嘉伦", "萧致远", "赵致远", "蒋宇宁", "顾震南", "余安琪", "熊岚", "卢子韬",
"孔杰宏", "周子韬", "黄睿", "史璐", "赵震南", "杜安琪", "赵致远", "石詩涵", "龚杰宏", "丁安琪", "黄杰宏", "傅睿", "戴嘉伦", "郝杰宏", "傅晓明", "孟嘉伦", "段睿", "戴致远", "石安琪", "汪詩涵",
"贾云熙", "邱子韬", "吴杰宏", "贾岚", "曾震南", "许云熙", "吴宇宁", "唐岚", "常嘉伦", "曾岚", "袁嘉伦", "黄晓明", "韦致远", "莫安琪", "丁子韬", "雷云熙", "许秀英", "朱宇宁", "黎詩涵", "贾晓明",
"孔詩涵", "秦宇宁", "方子韬", "邵秀英", "冯宇宁", "何晓明", "方嘉伦", "熊秀英", "沈云熙", "顾秀英", "许致远", "胡宇宁", "陶子异", "叶安琪", "邱震南", "刘子异", "周宇宁", "黄云熙", "龚杰宏", "杜秀英",
"向子异", "马睿", "黄安琪", "于安琪", "金嘉伦", "龚璐", "杨致远", "戴嘉伦", "钟詩涵", "阎詩涵", "雷安琪", "宋杰宏", "田致远", "冯致远", "雷杰宏", "雷子异", "叶璐", "王子异", "冯子韬", "史宇宁"
};
var students = Enumerable.Range(1,50).Select(s => new {Id = s, Age = Random.Shared.Next(1,100), Name = names[s]});
students.Display();
```
Formatter.ListExpansionLimit 更改为自定义值
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter.ListExpansionLimit = 5;
students.Display();
```
上面的示例中通过设置Formatter.ListExpansionLimit = 5然后显示相同的列表对象.NET Interactive现在仅显示前五项后面跟着 ...(more)。
也可以通过设置`Formatter<T>.ListExpansionLimit`来限制特定类型的输出。需要注意的是这里的类型T必须与列表中的项完全匹配。
以下是一个使用int类型的示例
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter<int>.ListExpansionLimit = 3;
Enumerable.Range(1, 10).Display();
```
注意:有些以 ...more结尾有些以数字 more结尾。
这是因为List、List<T>、数组等,列举前就知道元素确切的数量,以 `(数字 more)`结尾;而像 IEnumerable<T>(Enumerable.Range 返回类型是IEnumerable<T>)之类的,因此在枚举整个序列之前,无法知道元素确切的数量;在这种情况下,.NET交互式格式化器在达到配置的ListExpansionLimit时会停止并不会继续计数剩余的序列, 以 `...(more)` 结尾
### 限制对象循环引用次数
有些对象存在引用循环。虽然.NET Interactive格式化器会遍历对象图但它为了避免输出过大和无限递归只会递归到特定深度。
以下是一个C#代码示例它定义了一个简单的Node类创建了一个引用循环并使用C#脚本的尾随表达式(相当于返回语句)对其进行格式化:
```csharp
public class Node
{
public Node Next { get; set; }
}
Node node1 = new();
Node node2 = new();
node1.Next = node2;
node2.Next = node1;
node1
```
这表明格式化器在格式化到深度6后停止了递归。这个深度可以通过Formatter.RecursionLimit方法进行更改
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter.RecursionLimit = 2;
node1
```
### 首选 MIME 类型
前面提到Polyglot 笔记本中用于格式化的默认 MIME 类型是 text/html。当使用 Display() 方法时,如果没有向 mimeType 参数传递值,或者在 C# 或 F# 中使用 return 语句或尾随表达式时,就会应用这个默认设置。这个默认设置可以全局更改,也可以针对特定类型更改。
以下示例将 Rectangle 的默认值更改为 text/plain。
```csharp
public class Student
{
public int Id {get;set;}
public string Name {get;set;}
public int Age {get;set;}
}
Microsoft.DotNet.Interactive.Formatting.Formatter.SetPreferredMimeTypesFor(typeof(Student), "text/plain");
new Student
{
Id = 1,
Name = "张三",
Age = 55
}
```
该方法可用于设置多个首选MIME类型。第二个参数是params参数它允许您传递多个值。
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter.SetPreferredMimeTypesFor
(
typeof(Student),
"text/plain",
"application/json"
);
new Student
{
Id = 1,
Name = "张三",
Age = 55
}
```
注册多个MIME时可以切换输出格式
单击 执行结果单元格的最左侧`...`, 选择 `更改演示文稿`在VS Code最上访会弹出选择窗口选择注册项中的一个就可以重新以选中项的格式重新显示结果。
### 替换默认的格式化类型
默认格式化器通常通过打印列表和属性来显示对象的值。输出主要是文本形式。如果你希望以不同的方式显示某种类型的内容,无论是不同的文本输出、图像还是图表,你可以通过为特定类型注册自定义格式化器来实现。这些类型可以是你自己定义的,也可以是其他.NET库中定义的。
一个常见的使用自定义格式化器的场景是渲染图表。一些NuGet包如Plotly.NET提供了.NET Interactive扩展利用此功能以交互式的HTML和JavaScript为基础生成输出。
注册自定义格式化器最简单的方法是使用Formatter.Register<T>方法,它有几个不同的重载版本。在笔记本中使用最友好、最方便的一个接受两个参数:
+ 委托:它接受你要注册的类型的对象,并返回一个字符串。在这里,你可以指定所需的字符串转换;
+ MIME类型只有当使用此MIME类型时才会调用你的自定义格式化器
下面的示例将 Rectangles 类的实例格式化为SVG矩形。
```csharp
public class Rectangle
{
public int Width {get;set;}
public int Height {get;set;}
}
Microsoft.DotNet.Interactive.Formatting.Formatter.Register<Rectangle>
(
formatter: //格式化方法:把类型对象,转化为输出字符串
rect => $"""
<svg width="100" height="100">
<rect
width="{rect.Width}"
height="{rect.Height}"
style="fill:rgb(0,255,200)"
/>
</svg>
""",
mimeType: //输出媒体类型
"text/html"
);
```
```csharp
/*
运行此代码后Rectangle对象将显示为图形矩形而不是属性值列表。
以下示例使用C#脚本尾随表达式语法该语法通常配置为在笔记本中使用text/html MIME类型。
*/
new Rectangle(){Width = 100, Height = 50}
```
特别指出:当在列表中遇到自定义类型或作为对象属性时,仍将调用自定义格式化程序
```csharp
new[]
{
new Rectangle(){Width = 200, Height = 50},
new Rectangle(){Width = 200, Height = 100}
}
```
```csharp
//具有 Rectangle 类型属性的匿名对象
new {
Name = "Example",
Rectangle = new Rectangle(){ Width=100, Height=50 }
}
```
### 打开泛型类型
可以通过使用开放泛型类型定义作为键来指定格式化程序。以下代码将为所有类型的 T 的 List<T> 变体注册一个格式化程序,并打印每个元素及其哈希代码。(请注意,必须强制转换对象才能迭代其项。
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter.Register
(
type: typeof(List<>),
formatter: (list, writer) =>
{
foreach (var obj in (IEnumerable)list)
{
writer.WriteLine($"{obj} ({obj.GetHashCode()})");
}
}, "text/html"
);
```
```csharp
//运行上述代码后,以下内容将不再仅打印列表中的值 ["one","two","three"]
//变为one (254814599) two (656421459) three (-1117028319)
var list = new List<string> { "one", "two", "three" };
list
```
### TypeFormatterSource 特性类
Formatter.Register方式外另一种注册自定义格式化程序的方式是使用 TypeFormatterSourceAttribute 修饰类型。如果您想直接在笔记本中重新定义格式化程序设置,这不是最方便的方法。但是,如果您正在编写 .NET Interactive 扩展,或者编写包含某些类型的自定义格式的库或应用程序,则建议使用此方法。其中一个原因是基于属性的方法更简单。另一个原因是,调用 Formatter.ResetToDefault 时不会清除基于属性的格式化程序自定义,而使用 Formatter.Register 配置的格式化程序会被清除。您可以将基于属性的注册方法视为为类型设置默认格式的一种方式。
基于属性的格式化程序注册有两种方法:一种用于项目引用时,另一种用于项目不引用 Microsoft.DotNet.Interactive.Formatting 时
如果您已经引用了 Microsoft.DotNet.Interactive.Formatting ,例如,因为您正在编写 .NET Interactive 扩展,那么您可以使用 中定义的 TypeFormatterSourceAttribute 来修饰需要自定义格式的类型 Microsoft.DotNet.Interactive.Formatting 。下面是一个示例:
```csharp
[Microsoft.DotNet.Interactive.Formatting.TypeFormatterSource(typeof(MyFormatterSource))]
public class MyTypeWithCustomFormatting
{
}
//带Mime类型
[Microsoft.DotNet.Interactive.Formatting.TypeFormatterSource
(
typeof(MyFormatterSource), PreferredMimeTypes = new[] { "text/html", "application/json" }
)]
public class MyTypeWithCustomFormatting2
{
}
//TypeFormatterSourceAttribute 指定的格式化程序源必须实现 ITypeFormatterSource并且必须具有空构造函数。它不需要是 public 类型
public class MyFormatterSource : Microsoft.DotNet.Interactive.Formatting.ITypeFormatterSource
{
public IEnumerable<Microsoft.DotNet.Interactive.Formatting.ITypeFormatter> CreateTypeFormatters()
{
return new Microsoft.DotNet.Interactive.Formatting.ITypeFormatter[]
{
new Microsoft.DotNet.Interactive.Formatting.PlainTextFormatter<MyTypeWithCustomFormatting>(context =>
$"Hello from {nameof(MyFormatterSource)} using MIME type text/plain"),
new Microsoft.DotNet.Interactive.Formatting.HtmlFormatter<MyTypeWithCustomFormatting>(context =>
$"Hello from {nameof(MyFormatterSource)} using MIME type text/html")
};
}
}
```
一个完整例子:
```csharp
[AttributeUsage(AttributeTargets.Class)]
internal class TypeFormatterSourceAttribute : Attribute
{
public TypeFormatterSourceAttribute(Type formatterSourceType)
{
FormatterSourceType = formatterSourceType;
}
public Type FormatterSourceType { get; }
public string[] PreferredMimeTypes { get; set; }
}
internal class MyConventionBasedFormatterSource
{
public IEnumerable<object> CreateTypeFormatters()
{
yield return new MyConventionBasedFormatter { MimeType = "text/html" };
}
}
internal class MyConventionBasedFormatter
{
public string MimeType { get; set; }
public bool Format(object instance, System.IO.TextWriter writer)
{
if (instance is MyTypeWithCustomFormatting myObj)
{
writer.Write($"<div>Custom formattering for {myObj}</div>");
return true;
}
else
{
return false;
}
}
}
```
### 重置格式设置
在尝试不同的格式设置配置时,您可能会发现需要将所有内容重置为首次启动内核时看到的默认值。您可以轻松执行此作:
```csharp
Microsoft.DotNet.Interactive.Formatting.Formatter.ResetToDefault();
```
### 如何选择格式化程序
可以注册多个可能适用于同一类型的格式化程序。例如,可以为 object、IEnumerable<string> 和 IList<string> 注册格式化程序,其中任何一个都可能合理地应用于 List<string> 的实例。由于这些原因,了解如何选择 formatter 可能很有用。
为 A 类型的对象选择适用的格式化程序,如下所示:
+ 选择 MIME 类型:
+ 选择与 A 相关的最具体的用户注册 MIME 类型首选项
+ 如果没有相关的用户注册的 MIME 类型,则使用配置的默认 MIME 类型
+ 选择一个格式化程序:
+ 选择与 A 相关的最具体的用户注册格式化程序
+ 如果没有相关的用户注册格式化程序,则选择默认格式化程序
> 在这里,“最具体”是指类和接口层次结构。如果顺序完全一致或存在其他冲突,则首选较新的注册。当泛型类型的类型定义相同时,泛型类型的类型实例化优先于泛型格式化程序。
> MIME 类型的默认格式化程序集始终包括 object 的格式化程序
```csharp
using System.IO;
using Microsoft.DotNet.Interactive.Formatting;
ITypeFormatter formatter = Formatter.GetPreferredFormatterFor( typeof(Rectangle), Formatter.DefaultMimeType);
var rect = new Rectangle { Width = 100, Height = 50 };
var writer = new StringWriter();
formatter.Format(rect, writer);
Console.WriteLine(writer.ToString());
```
Examples 例子, 用于说明 Formatter 选择的工作原理
+ 如果您为类型 A 注册格式化程序,则该格式化程序将用于类型 A 的所有对象(直到稍后指定类型 A 的替代格式化程序)
+ 如果为 System.Object 注册格式化程序,则它优先于所有其他格式化程序,但其他更具体的用户定义的格式化程序除外
+ 如果为任何 sealed 类型注册格式化程序,则它优先于所有其他格式化程序(除非为该类型指定了更多格式化程序)
+ 如果注册 List<> 和 List<int> 格式化程序,则 List<int> 格式化程序优先用于 List<int> 类型的对象,而 List<> 格式化程序优先用于其他泛型实例化,例如 List<string>

File diff suppressed because it is too large Load Diff

@ -38,7 +38,8 @@
},
"outputs": [],
"source": [
"#r \"nuget:Microsoft.Dotnet.Interactive.SqlServer,*-*\""
"#r \"nuget:Microsoft.Dotnet.Interactive.SqlServer,*-*\"\n",
"#r \"nuget:Microsoft.Identity.Client,4.66.2\""
]
},
{
@ -302,24 +303,6 @@
"var c = context.Database.ExecuteSql(fs);\n",
"display(c);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "sql-DemoEF"
},
"polyglot_notebook": {
"kernelName": "sql-DemoEF"
}
},
"outputs": [],
"source": [
"#!sql-DemoEF\n",
"\n",
"var data = from "
]
}
],
"metadata": {

File diff suppressed because one or more lines are too long

@ -1,268 +0,0 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"连接到 SQLite 数据库\n",
"============================== "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"连接到 SQLite 数据库,并操作数据。注意:此功能在 Microsoft.DotNet.Interactive.ExtensionLab 扩展库中,要先引用 Nuget 包。"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 设置Nuget包源"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"#i \"https://api.nuget.org/v3/index.json\""
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 引用 Nuget 包"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"#r \"nuget: Microsoft.DotNet.Interactive.ExtensionLab,*-*\""
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 连接到 SQLite 数据库"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"引用扩展库后,使用 #!connect sqlite 命令连接到SQLite数据库"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"#!connect sqlite --kernel-name MySQLiteDemo \"Data Source=sqlite\\\\SQLiteDemo.db\"\n",
"\n",
"/*\n",
" 相对目录位置\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=Database\\SQLiteDemo.db;\"\n",
" \n",
" 缓存共享\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=Database\\SQLiteDemo.db;Cache=Shared;\"\n",
"\n",
" 使用带密码\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=SQLiteDemo.db;Cache=Shared;Password=MyEncryptionKey;\"\n",
" \n",
" 只读模式\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=SQLiteDemo.db;Mode=ReadOnly\"\n",
"\n",
" 读写创建模式\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=SQLiteDemo.db;Mode=ReadWriteCreate\"\n",
"\n",
" 读写模式\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=SQLiteDemo.db;Mode=ReadWrite\"\n",
"\n",
" 私有内存模式\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=:memory:\"\n",
"\n",
" 共享内存模式\n",
" #!connect sqlite --kernel-name MySQLiteDemo \"Data Source=Sharable;Mode=Memory;Cache=Shared\"\n",
"*/"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 使用连接操作数据库"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "sql-MySQLiteDemo"
},
"polyglot_notebook": {
"kernelName": "sql-MySQLiteDemo"
}
},
"outputs": [],
"source": [
"#!sql-MySQLiteDemo\n",
"\n",
"select * from person;"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## C#中使用"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"//直接引用包,使用类库操作就可以了,不需要使用 上下文连接"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": ".NET"
},
{
"aliases": [
"C#",
"c#"
],
"languageName": "C#",
"name": "csharp"
},
{
"aliases": [
"F#",
"f#"
],
"languageName": "F#",
"name": "fsharp"
},
{
"aliases": [],
"languageName": "HTML",
"name": "html"
},
{
"aliases": [],
"languageName": "KQL",
"name": "kql"
},
{
"aliases": [],
"languageName": "Mermaid",
"name": "mermaid"
},
{
"aliases": [
"powershell"
],
"languageName": "PowerShell",
"name": "pwsh"
},
{
"aliases": [],
"languageName": "SQL",
"name": "sql"
},
{
"aliases": [],
"languageName": "T-SQL",
"name": "sql-Demo"
},
{
"aliases": [],
"languageName": "T-SQL",
"name": "sql-DemoEF"
},
{
"aliases": [],
"languageName": "SQLite",
"name": "sql-MySQLiteDemo"
},
{
"aliases": [],
"name": "value"
},
{
"aliases": [
"frontend"
],
"name": "vscode"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

@ -0,0 +1,304 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fdfbe9e1",
"metadata": {},
"source": [
"使用PocketView操作Html\n",
"======================="
]
},
{
"cell_type": "markdown",
"id": "a17a651c",
"metadata": {},
"source": [
"PocketView是一个API用于使用C#代码用HTML的术语简明地编写HTML。就像HTML方法一样它返回一个实现IHtmlCent的对象因此输出将被假定为有效的HTML并呈现到您的笔记本中。这里有一个例子"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5859c1f7",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"using Microsoft.DotNet.Interactive.Formatting;\n",
"using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags;\n",
"\n",
"PocketView pocketView = PocketViewTags.span(img[src:\"https://www.baidu.com/img/flexible/logo/pc/result.png\",style:\"height:1em\"],HTML(\"&nbsp;\"), a[href:@\"https://www.baidu.com\"](i(\"百度\")));\n",
"pocketView.Display();\n",
"\n",
"//display(pocketView);"
]
},
{
"cell_type": "markdown",
"id": "ed5a269f",
"metadata": {},
"source": [
"解析上面的代码:\n",
"+ 调用span方法传递三个参数img方法结果、HTML方法结果、a方法结果\n",
"+ img方法是通过一个索引器调用的该索引器传递了几个命名参数src和style; \n",
"+ HTML方法有一个字符串参数 `&nbsp;` 即空格的 html 转义字符;\n",
"+ a方法有另一个索引器参数href和一个参数在本例中是对i方法的调用\n",
"\n",
"实质以C#对象的方式,组装了一段 html代码片断"
]
},
{
"cell_type": "markdown",
"id": "8d862b6e",
"metadata": {},
"source": [
"通过将PocketView转换为字符串您可以看到它产生的实际HTML该字符串将以纯文本而不是HTML显示"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"//display(pocketView.ToDisplayString());\n",
"display(pocketView.ToString());"
]
},
{
"cell_type": "markdown",
"id": "9ef8c896",
"metadata": {},
"source": [
"由于HTML难以使用静态类型语言进行简洁表示PocketView采用了动态类型。这使得你可以使用任意索引器名称来指定HTML属性。PocketViewTags上的每个方法都返回一个动态的PocketView。让我们更详细地了解你可以用PocketView实现的功能。\n",
"\n",
"注意:在本节的代码示例中,通过在笔记本中运行`using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags`你可以直接调用PocketView方法而无需类名限定。\n",
"\n",
"如上所述你可以使用方括号限定符来指定HTML属性,小括号填充HTML元素内容:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"//span html片断\n",
"PocketView spanElement = span[style:\"font-style:italic\"](\"你好,我带了倾斜样式\");\n",
"spanElement.Display();\n",
"\n",
"//图片 html片断\n",
"PocketView imgElement = img[src:\"https://www.baidu.com/img/flexible/logo/pc/result.png\",style:\"height:1em\", title:\"百度图片\"];\n",
"imgElement.Display();\n",
"\n",
"//超级连接 html片断\n",
"PocketView linkElement = a[href:@\"https://www.baidu.com\"](i(\"百度连接\"));\n",
"linkElement.Display();"
]
},
{
"cell_type": "markdown",
"id": "8fe067db",
"metadata": {},
"source": [
"如果你将一个字符串传递给PocketView它会为你进行HTML编码"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"//sapn本身作为html标签被当作Html显示但span里的html样式的内容不被当作html渲染而是编码后直接显示\n",
"PocketView view = span(\"<div>对我 进行编码</div>\");\n",
"//原样显示html片断自身不作为html元素进行渲染\n",
"display(view);\n",
"\n",
"//显示被html编码过的原始字符串\n",
"display(view.ToString());"
]
},
{
"cell_type": "markdown",
"id": "2376610d",
"metadata": {},
"source": [
"这就是HTML方法派上用场的地方。如果你想将一个字符串传递给PocketView但又不希望它被HTML编码你可以简单地将该字符串用HTML方法包裹起来"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"//HTML方法后就作为 html片断进行 \"渲染\" 了\n",
"PocketView view2 = span(HTML(\"<div>Don't encode me!</div>\"));\n",
"display(view2);\n",
"display(view2.ToString());"
]
},
{
"cell_type": "markdown",
"id": "bd47366d",
"metadata": {},
"source": [
"HTML简单地将一个字符串捕获到一个实现IHtmlContent接口的实例中。该接口用于指示该值不应被HTML编码而是应被视为有效的HTML并直接呈现。\n",
"\n",
"了解了这一点可能不会感到惊讶的是PocketView本身也实现了IHtmlContent接口。\n",
"\n",
"你还可以将其他类型的对象传递给PocketView。当你这样做时它们会使用纯文本格式化器进行格式化该格式化器默认会扩展对象的属性。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"PocketView view3 = b(\n",
" new {Fruit=\"apple\", Texture=\"smooth\"}\n",
");\n",
"\n",
"display(view3)"
]
},
{
"cell_type": "markdown",
"id": "b7c66e90",
"metadata": {},
"source": [
"由于目前.NET Interactive的格式化API不支持为嵌套的HTML片段生成格式化器PocketView会回退到text/plain格式化器来描述传递对象的属性。\n",
"\n",
"你也可以将对象列表传递给PocketView。这对于从数据生成HTML非常有用"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"var fruits = new []{\"apple\",\"banana\",\"cherry\"};\n",
"var colors = new []{\"green\",\"#F1C40F\",\"red\"};\n",
"\n",
"\n",
"ul(\n",
" fruits.Zip(colors).Select(x => li[style:$\"color:{x.Item2}\"](x.Item1))\n",
")"
]
},
{
"cell_type": "markdown",
"id": "cc60cd12",
"metadata": {},
"source": [
"总结:其实这样的方式 \"组装\"html页面或片断会非常繁琐只适合临时做一些简单的html组装\n",
"方案:\n",
"+ 使用 html 内核: 但有个最大问题是\"html内核不能使用共享数据\";只适合纯静态页面;\n",
"+ 使用 javascript 内核: 虽然能使用 \"共享数据\"功能但js内核长处是操作现有html并非生成html;\n",
"+ 使用 razor 或 blazor 库像razor或blazor页面或组件一样就非常方便了;`非常推荐的终极解决方案` 唯一缺点是智能提示差可以在VS里写好粘贴过来哈"
]
},
{
"cell_type": "markdown",
"id": "20446659",
"metadata": {},
"source": [
"使用 Razor的例子:体验下方不方便(后面专题讲解)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [],
"source": [
"#r \"nuget:RazorInteractive\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "razor"
}
},
"outputs": [],
"source": [
"#!razor\n",
"@{\n",
" \n",
" var dic = new Dictionary<string, string>()\n",
" {\n",
" {\"apple\",\"green\"},\n",
" {\"banana\",\"#F1C40F\"},\n",
" {\"cherry\",\"red\"},\n",
" };\n",
"}\n",
"\n",
"<ul>\n",
" @foreach(var item in dic)\n",
" {\n",
" <li style='color:@item.Value'>@item.Key</li>;\n",
" }\n",
"</ul>"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"languageName": "csharp",
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -0,0 +1,131 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a59722d6",
"metadata": {},
"source": [
"Polyglot Netebooks 中添加Jupyter内核支持Python语言\n",
"===================================================="
]
},
{
"cell_type": "markdown",
"id": "23bcd178",
"metadata": {},
"source": [
"使用魔术命令 \n",
"\n",
"无Conda环境`#!connect jupyter --kernel-name pythonkernel --kernel-spec python3`\n",
"有Conda环境`#!connect jupyter --kernel-name pythonkernel --conda-env base --kernel-spec python3`\n",
"\n",
"实测有缺点:\n",
"+ 不能重复执行:重复执行会报错\n",
"+ 连接字符串必须是真实字符串:不能是变量,不灵活;明文\"不安全\",比如演示环境\n",
"\n",
"变通用法在C#程序中,拼接好魔术命令`#!connect`,再发送给内核执行"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b10341c4",
"metadata": {
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"名为 Pythonkernel 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!\r\n"
]
}
],
"source": [
"//魔术命令\n",
"// #!connect jupyter --kernel-name pythonkernel --kernel-spec python3\n",
"// #!connect jupyter --kernel-name pythonkernel --conda-env base --kernel-spec python3\n",
"\n",
"using Microsoft.DotNet.Interactive;\n",
"using Microsoft.DotNet.Interactive.Commands;\n",
"\n",
"//优化方式\n",
"{\n",
" //内核名:\n",
" string magicCommandKernelName = \"Pythonkernel\";\n",
"\n",
" //引入内核:可重复执行\n",
" if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(magicCommandKernelName) == null)\n",
" {\n",
" var connectKernelCode = $\"#!connect jupyter --kernel-name {magicCommandKernelName} --kernel-spec python3\";\n",
" await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode, \"csharp\"));\n",
" }\n",
" else\n",
" {\n",
" Console.WriteLine($\"名为 {magicCommandKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!\");\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"polyglot_notebook": {
"kernelName": "pythonkernel"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello,python3!\n"
]
}
],
"source": [
"#!Pythonkernel\n",
"# 写 python 代码\n",
"print(\"hello,python3!\");"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"languageName": "csharp",
"name": "csharp"
},
{
"aliases": [],
"languageName": "python",
"name": "pythonkernel"
},
{
"aliases": [],
"languageName": "python",
"name": "Pythonkernel"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading…
Cancel
Save