csharp(1)

🌸 NAME 🌸

bestie, this is the csharp(1) page, plucked straight out of the General Commands Manual β€” it's the Interactive C# Shell and Scripting moment. yes, C#, live, in your terminal, reacting to every keystroke ✨


✨ SYNOPSIS ✨

csharp [--attach PID] [-e EXPRESSION] [file1 [file2]] [compiler-options]
[--|-s script-options]

πŸ’… DESCRIPTION πŸ’…

so the csharp command is an interactive C# shell and scripting host β€” it lets you type C# statements and expressions straight into the command line and get them evaluated, or run whole C# scripts. and get this: the regular mcs command line options work in this version of the compiler too, so you're not losing anything 🫢

Any files you drop on the command line get loaded and executed as scripts. no extra ceremony, it just runs them.

Starting with Mono 2.10, csharp can be used as an interpreter that executables run when they're flagged with the Unix execute attribute πŸ”₯ to pull that off, make the first line of your C# source look exactly like this:

#!/usr/bin/csharp
Console.WriteLine ("Hello, World");

Starting with Mono 5.0, command line arguments may now be passed to the csharp command by specifying either the -s or -- (script) options ✨

The -s option is ideal for interpreting executable scripts that utilize shebang syntax (introduced in Mono 2.10). This lets command line arguments be passed to and consumed cleanly by the script:

#!/usr/bin/csharp -s
foreach (var arg in Args)
  Console.WriteLine ($"script argument: {arg}");

πŸŽ€ OPTIONS πŸŽ€

so the commands accept all of the commands that are available to the mcs command, meaning you can reference assemblies, specify paths, set the language level, and so on, all from the command line πŸ’– And on top of that, these extra command line options are supported:

  • -s SCRIPT_FILE β€” this one is ideal for authoring executable scripts that utilize the Unix shebang feature. Unix will implicitly append as an argument the path of the script to execute. When the executable is invoked, any arguments then passed to it will be available in the Args global. Example: #!/usr/bin/env csharp -s
  • -- β€” any arguments that follow will not be passed to the compiler driver, and instead will be made available in the Args global. Example: csharp -- a b c will result in Args = { "a", "b", "c" } in the interactive shell.
  • --attach β€” this is an advanced option and should only be used if you have a deep understanding of multi-threading. It's available on the csharp command and allows the compiler to be injected into other processes 🫠 This is done by injecting the C# shell in a separate thread that runs concurrently with your application. Which means you must take special measures to avoid crashing the target application while using it. For example, you might have to take the proper locks before issuing any commands that might affect the target process state, or sending commands through a method dispatcher. (also, yes, the original spells it "availble" β€” we keep the lore intact πŸ’€)
  • -e EXPRESSION β€” this will evaluate the specified C# EXPRESSION and exit πŸƒβ™€οΈ

πŸ¦‹ OPERATION πŸ¦‹

Once you launch the csharp command, you will be greeted with the interactive prompt:

$ csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp>

A number of namespaces are pre-defined with C#, and these include System, System.Linq, System.Collections and System.Collections.Generic ✨ Unlike the compiled mode, it is possible to add new using statements as you type code, for example:

csharp> new XmlDocument ();
<interactive>(1,6): error CS0246: The type or namespace name `XmlDocument' could not be found. Are you missing a using directive or an assembly reference?
csharp> using System.Xml;
csharp> new XmlDocument ();
System.Xml.XmlDocument

Every time a command is typed, the scope of that command is one of a class that derives from the class Mono.CSharp.InteractiveBase πŸ‘‘ This class defines a number of static properties and methods. To display a list of available commands, access the help property:

csharp> help;
"Static methods:
  LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)
  [...]
  ShowVars ();       - Shows defined local variables.
  ShowUsing ();      - Show active using decltions.
  help;
"
csharp>

(that "decltions" is not a typo we introduced, it's canon, leave it alone πŸ™ˆ)

When expressions are entered, the C# shell will display the result of executing the expression:

csharp> Math.Sin (Math.PI/4);
0.707106781186547
csharp> 1+1;
2
csharp> "Hello, world".IndexOf (',');
5

The C# shell uses the ToString() method on the returned object to display the object, and honestly this sometimes can be limiting, because objects that do not override the ToString() method will get the default behavior from System.Object, which is merely to display their type name:

csharp> var a = new XmlDocument ();
csharp> a;
System.Xml.Document
csharp> csharp> a.Name;
"#document"
csharp>

A few datatypes are handled specially by the C# interactive shell β€” like arrays, System.Collections.Hashtable, objects that implement System.Collections.IEnumerable and IDictionary β€” and those get rendered specially instead of just using ToString ():

csharp> var pages = new Hashtable () {
      >  { "Mono",    "http://www.mono-project.com/" },
      >  { "Linux",   "http://kernel.org" } };
csharp> pages;
{{ "Mono", "http://www.mono-project.com/" }, { "Linux", "http://kernel.org" }}

It is possible to use LINQ directly in the C# interactive shell, since the System.Linq namespace has been imported at startup πŸ’œ The following sample gets a list of all the files that have not been accessed in a week from /tmp:

csharp> using System.IO;
csharp> var last_week = DateTime.Now - TimeSpan.FromDays (7);
csharp> var old_files = from f in Directory.GetFiles ("/tmp")
      >   let fi = new FileInfo (f)
      >   where fi.LastAccessTime < LastWeek select f;
csharp>

You can of course print the results in a single statement as well:

csharp> using System.IO;
csharp> var last_week = DateTime.Now - TimeSpan.FromDays (7);
csharp> from f in Directory.GetFiles ("/tmp")
      >   let fi = new FileInfo (f)
      >   where fi.LastAccessTime < last_week select f;
[...]
csharp>

LINQ and its functional foundation produce on-demand code for IEnumerable return values. For instance, the return value from a using from is an IEnumerable that is evaluated on demand. The automatic rendering of IEnumerables on the command line will trigger the IEnumerable pipeline to execute at that point, instead of having its execution delayed until a later point πŸ‘€

If you want to avoid having the IEnumerable rendered at this point, simply assign the value to a variable. problem solved, bestie πŸ’…

Unlike compiled C#, the type of a variable can be changed if a new declaration is entered, for example:

csharp> var a = 1;
csharp> a.GetType ();
System.Int32
csharp> var a = "Hello";
csharp> a.GetType ();
System.String
csharp> ShowVars ();
string a = "Hello"

In the case that an expression or a statement is not completed in a single line, a continuation prompt is displayed, for example:

csharp> var protocols = new string [] {
      >    "ftp",
      >    "http",
      >    "gopher"
      > };
csharp> protocols;
{ "ftp", "http", "gopher" }

Long running computations can be interrupted by using the Control-C sequence:

csharp> var done = false;
csharp> while (!done) { }
Interrupted!
System.Threading.ThreadAbortException: Thread was being aborted
  at Class1.Host (System.Object& $retval) [0x00000]
  at Mono.CSharp.InteractiveShell.ExecuteBlock (Mono.CSharp.Class host, Mono.CSharp.Undo undo) [0x00000]
csharp>

πŸ‘‘ INTERACTIVE EDITING πŸ‘‘

The C# interactive shell contains a line-editor that provides more advanced command line editing functionality than the operating system provides ✨ These are available in the command line version; the GUI versions use the standard Gtk# key bindings.

The command set is similar to many other applications (cursor keys) and incorporates some of the Emacs commands for editing as well as a history mechanism too πŸŽ€

The following keyboard input is supported:

  • Home Key, Control-a β€” goes to the beginning of the line.
  • End Key, Control-e β€” goes to the end of the line.
  • Left Arrow Key, Control-b β€” moves the cursor back one character.
  • Right Arrow Key, Control-f β€” moves the cursor forward one character.
  • Up Arrow Key, Control-p β€” goes back in the history, replaces the current line with the previous line in the history.
  • Down Arrow Key, Control-n β€” moves forward in the history, replaces the current line with the next line in the history.
  • Return β€” executes the current line if the statement or expression is complete, or waits for further input.
  • Control-C β€” cancel the current line being edited. This will kill any currently in-progress edits or partial editing and go back to a toplevel definition.
  • Backspace Key β€” deletes the character before the cursor
  • Delete Key, Control-d β€” deletes the character at the current cursor position.
  • Control-k β€” erases the contents of the line until the end of the line and places the result in the cut and paste buffer.
  • Alt-D β€” deletes the word starting at the cursor position and appends into the cut and paste buffer. By pressing Alt-d repeatedly, multiple words can be appended into the paste buffer.
  • Control-Y β€” pastes the content of the kill buffer at the current cursor position.
  • Control-Q β€” this is the quote character. It allows the user to enter control-characters that are otherwise taken by the command editing facility. Press Control-Q followed by the character you want to insert, and it will be inserted verbatim into the command line.
  • Control-D β€” terminates the program. This terminates the input for the program.

✨ STATIC PROPERTIES AND METHODS ✨

okay so listen πŸ’– β€” the base class that all your statements and expressions run inside? its methods and properties are static, which means you can just... call them straight from the shell. no ceremony. no new. it's giving effortless. 🫢

here's the whole menu, bestie:

  • Args β€” a super easy-to-consume array of literally any arguments you pass after either -s or -- on the command line. ideal for self-executing scripts that use the -s option, iykyk. πŸ’…
  • void LoadAssembly(string assembly) β€” loads up the assembly you hand it. same energy as passing the compiler the -r: flag with that string. ✨
  • void LoadPackage(string package) β€” imports the package you named. equivalent to invoking the compiler with the -pkg: flag with that string. πŸŽ€
  • string Prompt { get; set } β€” the prompt the shell uses. it defaults to the value "csharp> ". 🌸
  • string ContinuationPrompt { get; set; } β€” the prompt the shell shows when it needs more input to finish off your expression or statement. it's the "wait bestie I'm not done talking" prompt. 😭
  • void ShowVars() β€” displays every variable you've defined so far, plus their types. heads up: in the csharp shell, declaring a new variable will shadow previous variable declarations β€” which is not how it works in C# when it's compiled. different vibe, same name. πŸ‘‘
  • void ShowUsing() β€” displays all the using statements currently in effect. 🌈
  • TimeSpan Time (Action a) β€” the handy lil routine that times how long some code takes to run. the parameter is an Action delegate, and the return value is a TimeSpan. for example:
csharp> Time (() => { for (int i = 0; i < 5; i++) Console.WriteLine (i);});
0
1
2
3
4
00:00:00.0043230
csharp>

the return value is a TimeSpan, so you can stash it in a variable for all your benchmarking purposes. ⭐


πŸ–₯️ GUI METHODS AND PROPERTIES πŸ–₯️

beyond everything the console version gives you, the GUI version has a handful of extra properties. no cap. πŸ’œ

for example, there's a "PaneContainer" Gtk.Container exposed that you can use to host Gtk# widgets while you're prototyping, and there's the "MainWindow" property that hands you access to the current toplevel window. main character window energy, fr fr. πŸ‘‘


πŸš€ STARTUP FILES πŸš€

the C# shell loads all the Mono assemblies and C# script files it finds in the ~/.config/csharp directory on Unix. and bestie, order matters: the assemblies get loaded before the source files do. πŸ’…

C# script files are files with the .cs extension, and they should only contain statements and expressions β€” they can not contain full class definitions (at least not as of Mono 2.0). if you want full class definitions, compile them into dlls and drop those dlls in that directory instead. periodt. πŸŽ€


πŸ‘‘ AUTHORS πŸ‘‘

the Mono C# Compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar and Raja Harinath. the development was funded by Ximian, Novell and Marek Safar. legends only. 🫢✨


πŸ“œ LICENSE πŸ“œ

the Mono Compiler Suite is released under the terms of the GNU GPL or the MIT X11. please read the accompanying COPYING file for the deets. alternative licensing for the compiler is available from Novell. 🌸


πŸ”— SEE ALSO πŸ”—


πŸ’€ BUGS πŸ’€

to report bugs in the compiler, you must file them on the bug tracking system, at: http://www.mono-project.com/community/bugs/ β€” go tell them everything, bestie, they want to know. πŸ™ˆ


πŸ“¬ MAILING LIST πŸ“¬

the Mono mailing lists are listed at http://www.mono-project.com/community/help/mailing-lists/ πŸ’Œ


🌈 MORE INFORMATION 🌈

the Mono C# compiler was developed by Novell, Inc (http://www.novell.com, http) and it's based on the ECMA C# language standard, available right here: http://www.ecma.ch/ecma1/STAND/ecma-334.htm πŸ“š

the home page for the Mono C# compiler lives at http://www.mono-project.com/docs/about-mono/languages/csharp/, and info about the interactive mode for C# is at http://mono-project.com/docs/tools+libraries/tools/repl/ ✨


and that's a wrap on csharp(1) bestie!! this page is from 22 March 2017, and it's the manpage for the C# shell β€” you ate that whole read, I'm so proud. πŸ₯ΉπŸ’– go write some scripts, time some things, load some assemblies. slay. πŸ’…πŸŽ€πŸ¦‹