{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b42c0b7a",
   "metadata": {},
   "source": [
    "使用技巧与总结\n",
    "============"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a42a4a9",
   "metadata": {},
   "source": [
    "## 使用技巧"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d22d827",
   "metadata": {},
   "source": [
    "### 善用花括号"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2f12264",
   "metadata": {},
   "source": [
    "+ 隔离使用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"dni-plaintext\"><pre>3</pre></div><style>\r\n",
       ".dni-code-hint {\r\n",
       "    font-style: italic;\r\n",
       "    overflow: hidden;\r\n",
       "    white-space: nowrap;\r\n",
       "}\r\n",
       ".dni-treeview {\r\n",
       "    white-space: nowrap;\r\n",
       "}\r\n",
       ".dni-treeview td {\r\n",
       "    vertical-align: top;\r\n",
       "    text-align: start;\r\n",
       "}\r\n",
       "details.dni-treeview {\r\n",
       "    padding-left: 1em;\r\n",
       "}\r\n",
       "table td {\r\n",
       "    text-align: start;\r\n",
       "}\r\n",
       "table tr { \r\n",
       "    vertical-align: top; \r\n",
       "    margin: 0em 0px;\r\n",
       "}\r\n",
       "table tr td pre \r\n",
       "{ \r\n",
       "    vertical-align: top !important; \r\n",
       "    margin: 0em 0px !important;\r\n",
       "} \r\n",
       "table th {\r\n",
       "    text-align: start;\r\n",
       "}\r\n",
       "</style>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "你"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "//教学或演示时,常有对比功能,代码基本相同:花括号可以使用相同的变量名而不冲突\n",
    "{   //测试 where\n",
    "    var source = \"你 是 我的 宝儿 !\".Split(\" \");\n",
    "    var result = source.Where(s=> s.Length<=1).Count();\n",
    "    result.Display();\n",
    "}\n",
    "\n",
    "{   //测试 FirstOrDefault\n",
    "    var source = \"你 是 我的 宝儿 !\".Split(\" \");\n",
    "    var result = source.FirstOrDefault(s => s != \"!\");\n",
    "    result.Display();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fec882be",
   "metadata": {},
   "source": [
    "+ 文件代码折叠"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "//折叠整个代码块,方便全局查看\n",
    "{\n",
    "    //多行业务代码\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be07ffa2",
   "metadata": {},
   "source": [
    "### 提取共用功能"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5660e6f8",
   "metadata": {},
   "source": [
    "把共用的部分独立出来,方便统一管理和引用。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e359d4a",
   "metadata": {},
   "source": [
    "+ 单独笔记文件:Nuget包导入、公共命名空间引用、共用对象、共用方法等,放入单独笔记文件,在初始化单元格统一引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "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"
    }
   ],
   "source": [
    "//初始化单元格:必须先执行一次\n",
    "#!import \"./Base.ipynb\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61f85ef0",
   "metadata": {},
   "source": [
    "+ 单独的文件(C#、js等):提取公用功能到单独文件,方便统一调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前路径:c:\\Users\\ruyu\\Desktop\\多语言笔记学习\\Docs\r\n"
     ]
    }
   ],
   "source": [
    "//导入文件\n",
    "#!import \"./shared/script/tools.cs\"\n",
    "\n",
    "//使用功能\n",
    "{\n",
    "    var path = Tools.GetCurrentPath();\n",
    "    Console.WriteLine($\"当前路径:{path}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd538991",
   "metadata": {},
   "source": [
    "### 动态执行: 对只能执行一次等功能的代码可以动态执行,甚至动态添加单元格"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.DotNet.Interactive.SQLite, 1.0.0-beta.25177.1</span></li></ul></div></div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Loading extension script from `C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet.interactive.sqlite\\1.0.0-beta.25177.1\\interactive-extensions\\dotnet\\extension.dib`"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<details><summary>Query SQLite databases.</summary>\r\n",
       "    <p>This extension adds support for connecting to SQLite databases using the <code>#!connect sqlite</code> magic command. For more information, run a cell using the <code>#!sql</code> magic command.</p>\r\n",
       "    </details>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#r \"nuget:Microsoft.DotNet.Interactive.SQLite,*-*\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Kernel added: #!sql-SQLiteSharedKernel"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "/*  connect 和 import 等命令,只能执行一次\n",
    "    #!connect sqlite --kernel-name SQLiteSharedKernel --connection-string \"Data Source=.\\assets\\database\\study.db;\"\n",
    "*/\n",
    "\n",
    "using Microsoft.DotNet.Interactive;\n",
    "using Microsoft.DotNet.Interactive.Commands;\n",
    "\n",
    "//动态方法:可执行多次,且可使用变量等功能\n",
    "{\n",
    "    //内核名:魔法命令中的内核名,执行后会自动加 sql- 前缀,做为内核名被使用\n",
    "    string magicCommandKernelName =  \"SQLiteSharedKernel\";\n",
    "    string completeKernelName = \"sql-\" + magicCommandKernelName;\n",
    "\n",
    "    //引入内核:可重复执行\n",
    "    if(Microsoft.DotNet.Interactive.Kernel.Root.FindKernelByName(completeKernelName) == null)\n",
    "    {\n",
    "        var connectKernelCode = $\"#!connect sqlite --kernel-name {magicCommandKernelName} --connection-string \\\"{SharedDbConnect.SQLiteConnectionString}\\\"\";\n",
    "        await Kernel.Root.SendAsync(new SubmitCode( connectKernelCode,  \"csharp\"));\n",
    "    }\n",
    "    else\n",
    "    {\n",
    "        Console.WriteLine($\"名为 {completeKernelName} 的内核已存在。需要新内核时,请为--kernel-name参数使用不同的值, 本次执行不做任何更改!\");\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "//可动态添加单元格\n",
    "using Microsoft.DotNet.Interactive;\n",
    "using Microsoft.DotNet.Interactive.Commands;\n",
    "\n",
    "{//每执行一次,在下方添加代码单元格:可执行的\n",
    "    var command = new SendEditableCode(\n",
    "    \"csharp\", \n",
    "    \"Console.WriteLine(\\\"我是动态生成的代码单元哈!\\\");\");\n",
    "\n",
    "    var input = await Kernel.Root.SendAsync(command);\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "Console.WriteLine(\"我是动态生成的代码单元哈!\");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "333f49dd",
   "metadata": {},
   "source": [
    "### 了解各种路径"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Application.ExecutablePath => Application.ExecutablePath 只适用于WinForm\r\n",
      "Application.StartupPath => Application.StartupPath 只适用于WinForm\r\n",
      "AppContext.BaseDirectory => C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.617701\\tools\\net9.0\\any\\\r\n",
      "AppDomain.CurrentDomain.BaseDirectory => C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.617701\\tools\\net9.0\\any\\\r\n",
      "AppDomain.CurrentDomain.SetupInformation.ApplicationBase => C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.617701\\tools\\net9.0\\any\\\r\n",
      "Process.GetCurrentProcess().MainModule.FileName => C:\\Program Files\\dotnet\\dotnet.exe\r\n",
      "Environment.CurrentDirectory => c:\\Users\\ruyu\\Desktop\\多语言笔记学习\\Docs\r\n",
      "Environment.GetCommandLineArgs()[0] => C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.617701\\tools\\net9.0\\any\\Microsoft.DotNet.Interactive.App.dll\r\n",
      "Directory.GetCurrentDirectory => c:\\Users\\ruyu\\Desktop\\多语言笔记学习\\Docs\r\n",
      "Assembly.GetExecutingAssembly().Location => \r\n",
      "Assembly.GetEntryAssembly().Location => C:\\Users\\ruyu\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.617701\\tools\\net9.0\\any\\Microsoft.DotNet.Interactive.App.dll\r\n",
      "Assembly.GetExecutingAssembly().CodeBase => file:///C:/Program Files/dotnet/shared/Microsoft.NETCore.App/9.0.4/System.Private.CoreLib.dll\r\n",
      "Assembly.GetEntryAssembly().CodeBase => file:///C:/Users/ruyu/.nuget/packages/microsoft.dotnet-interactive/1.0.617701/tools/net9.0/any/Microsoft.DotNet.Interactive.App.dll\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "using System;\n",
    "using System.IO;\n",
    "using System.Threading;\n",
    "using System.Threading.Tasks;\n",
    "using System.Diagnostics;\n",
    "using System.Reflection;\n",
    "\n",
    "//查看各种程序路径\n",
    "{\n",
    "    var pathDic = new Dictionary<string, (string desc, string path)>() \n",
    "    {\n",
    "        //当前运行的exe的完整路径,包含exe文件名,只用于WinForm\n",
    "        {\"Application.ExecutablePath\",(\"程序集基完整路径(仅WinForm)\", \"Application.ExecutablePath 只适用于WinForm\") },\n",
    "\n",
    "        //程序的启动路径:只用于WinForm\n",
    "        {\"Application.StartupPath\",(\"程序集启动路径(仅WinForm)\", \"Application.StartupPath 只适用于WinForm\") },\n",
    "\n",
    "        //当前执行的exe或启动项目的路径,通过AppContext\n",
    "        {\"AppContext.BaseDirectory\",(\"执行或启动路径\", AppContext.BaseDirectory) },  \n",
    "\n",
    "        //当前执行的exe的目录,不包含exe名,使用AppDomain\n",
    "        {\"AppDomain.CurrentDomain.BaseDirectory\",(\"程序集解析程序用于探测程序集的基目录\", AppDomain.CurrentDomain.BaseDirectory) }, \n",
    "\n",
    "        //程序安装或启动基目录  包含应用程序的目录的名称\n",
    "        {\"AppDomain.CurrentDomain.SetupInformation.ApplicationBase\",(\"程序安装或启动基目录\", AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, \n",
    "\n",
    "        //当前进程的主模块路径,包含exe名\n",
    "        {\"Process.GetCurrentProcess().MainModule.FileName\",(\"当前进程的主模块路径\", Process.GetCurrentProcess()?.MainModule?.FileName) }, \n",
    "\n",
    "        //环境变量:用户当前工作目录的完整限定路径\n",
    "        {\"Environment.CurrentDirectory\",(\"用户当前工作目录的完整限定路径\", Environment.CurrentDirectory) }, \n",
    "\n",
    "        //环境变量:当前exe的完整路径,包含exe名,通过命令行参数\n",
    "        {\"Environment.GetCommandLineArgs()[0]\",(\"当前exe的完整路径\", Environment.GetCommandLineArgs()[0]) }, \n",
    "\n",
    "        //当前工作目录的路径(可变)\n",
    "        {\"Directory.GetCurrentDirectory\",(\"当前工作目录的路径(可变)\", Directory.GetCurrentDirectory()) },\n",
    "        \n",
    "        //当前Assembly的加载路径,包含dll或exe名\n",
    "        {\"Assembly.GetExecutingAssembly().Location\",(\"当前Assembly的加载路径\", Assembly.GetExecutingAssembly().Location) },\n",
    "\n",
    "        //入口程序集的路径\n",
    "        {\"Assembly.GetEntryAssembly().Location\",(\"入口程序集的路径\", Assembly.GetEntryAssembly()?.Location) },\n",
    "\n",
    "        //已过时:当前程序集的CodeBase路径,可能为file URI格式\n",
    "        {\"Assembly.GetExecutingAssembly().CodeBase\",(\"当前程序集的CodeBase路径\", Assembly.GetExecutingAssembly()?.CodeBase) },\n",
    "\n",
    "        //已过时:入口程序集的CodeBase路径,可能为file URI格式\n",
    "        {\"Assembly.GetEntryAssembly().CodeBase\",(\"入口程序集的CodeBase路径\", Assembly.GetEntryAssembly()?.CodeBase) },\n",
    "    };\n",
    "\n",
    "    var message = string.Empty;\n",
    "    foreach (var item in pathDic)\n",
    "    {\n",
    "        message += $\"{item.Key} => {item.Value.path}{Environment.NewLine}\";\n",
    "    }\n",
    "\n",
    "    Console.WriteLine(message);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e37e66e",
   "metadata": {},
   "source": [
    "## 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "913992ad",
   "metadata": {},
   "source": [
    "Polyglot Notebooks优点非常多,缺点也不少。有其非常适用的场景,也有其难以使用的地方。主要是用对地方,它就是神器!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c01fc2fb",
   "metadata": {},
   "source": [
    "### 优点:少说一些,文章已有说明"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b89044dd",
   "metadata": {},
   "source": [
    "+ 多语言可以混合使用\n",
    "+ 各语言内核之间可:共享变量\n",
    "+ 图文混排,非常适合:教学场景、学习笔记场景、功能演示场景、快速验证场景等"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d5c8cfe",
   "metadata": {},
   "source": [
    "### 缺点:个人总结,可能不很准确"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "source": [
    "+ 不支持调试:个人感觉是最大的缺点,不能调试代码太难受了。(虽然有一些变通的方法,但都比较难用, 增加复杂性功能也不好用);\n",
    "+ 暂时不支持 .net 项目的引用:可先编译,再引用编译过的Dll和nuget包。也能蛋疼,官方说在\"研究\",希望能研究好吧;\n",
    "+ 内置智能提示弱:功能弱、不稳定,与Visual Studio 差了百条街,甚至与VS Code本身都不是一个等级的; \n",
    "+ 代码折叠与显示弱:功能太弱;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b368390b",
   "metadata": {},
   "source": [
    "## Next(下一个)\n",
    "\n",
    "咱们CSDN视频课程见!"
   ]
  }
 ],
 "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": "SQLite",
      "name": "sql-SQLiteSharedKernel"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}