Comments 15
Кстати для заинтересованных в таких вещах существует открытый и кроссплатформенный проект dotnet/interactive. Я его использовал в юпитере, но можно использовать embedded kernel, как здесь.
Одна из перегрузок CSharpScript.Create принимает параметром тип глобального объекта.
Его методы будут доступны из скрипта глобально.(если он не статический то в Create и RunAsync можно сам объект передать)
Script<object> script = CSharpScript.Create(File.ReadAllText(Program.options.Script), options, typeof (ScriptHost), null);
script.RunAsync(scriptHost, null, new CancellationToken()).Wait();
//Уже в скрипте вызываем метод от глобального объекта
StartSession("some-args");
код декомпилированный(не помню где исходники проекта), но смысл должен быть понятен.
Собственно сам студийный C# Interactive работает по такому же принципу поидее, но там глобальный тип это Console.(можно WriteLine писать прям так)
Возможно, там просто в ScriptOptions указан. Если добавить в него System.Console, то можно будет просто написать WriteLine(...), точно так же, как при использовании "using static System.Console".
Спасибо, что напомнили, постараюсь добавить в статью
Я обычно "скриптингом" на C# занимаюсь через Powershell. Очень удобно, когда нужен простенький GUI, например:
$Assem = (
“System.Windows.Forms”,
"System.Drawing",
"System.Core",
"System.Data",
"System.Xml"
)
$Source = @”
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Infor.LMS.Utils.TranslationSearch
{
public class Form1: Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(10, 10);
this.label1.Name = "label1";
this.label1.Font = new System.Drawing.Font("Segoe UI", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.label1.Size = new System.Drawing.Size(148, 13);
this.label1.Text = "Hello world!";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(300, 200);
this.Controls.Add(this.label1);
this.Margin = new System.Windows.Forms.Padding(2);
this.Name = "Form1";
this.Text = "Hello World!";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
//End of codegen
public Form1()
{
InitializeComponent();
}
}
public static class Program
{
public static void Start()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
“@
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp
iex "[Infor.LMS.Utils.TranslationSearch.Program]::Start()"
Главное не принимать от клиентской стороны лямбда выражения, иначе это готовый remote code execution
С Microsoft.CodeAnalysis.CSharp.Scripting только одна проблема, если на .Net5 попытаться запаблишить как self-contained с флагом PublishSingleFile=true, то оно не работает (по крайней мере сейчас).
Скриптинг в C# или динамическое выполнение в runtime