Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Le app basate su file sono programmi contenuti all'interno di un singolo *.cs file compilato ed eseguito senza un file di progetto corrispondente (*.csproj). Le app basate su file sono ideali per l'apprendimento di C# perché hanno meno complessità: l'intero programma viene archiviato in un singolo file. Le app basate su file sono utili anche per la creazione di utilità della riga di comando. Nelle piattaforme Unix, le app basate su file possono essere eseguite usando #!direttive (shebang).
In questa esercitazione, farai:
- Creare un programma basato su file.
- Aggiungere il supporto di Unix shebang (
#!). - Leggere gli argomenti della riga di comando.
- Gestire l'input standard.
- Scrivere l'output dell'arte ASCII.
- Elaborare gli argomenti della riga di comando.
- Usare i risultati della riga di comando analizzati.
- Testare l'applicazione finale.
Si compila un programma basato su file che scrive testo come arte ASCII. L'app è contenuta in un singolo file, usa pacchetti NuGet che implementano alcune delle funzionalità di base.
Prerequisiti
- The .NET 10 SDK. Scaricarlo dal sito di download .NET.
- Visual Studio Code. Scaricarlo dalla home page di Visual Studio Code.
- (Facoltativo) Estensione C# DevKit per Visual Studio Code. Scaricarlo dal marketplace di Visual Studio Code.
Creare un programma basato su file
Aprire Visual Studio Code e creare un nuovo file denominato
AsciiArt.cs. Immettere il testo seguente:Console.WriteLine("Hello, world!");Salvare il file. Aprire quindi il terminale integrato in Visual Studio Code e digitare:
dotnet run AsciiArt.cs
La prima volta che si esegue questo programma, l'host dotnet compila il file eseguibile dal file di origine, archivia gli artefatti di compilazione in una cartella temporanea, quindi esegue il file eseguibile creato. È possibile verificare questa esperienza digitando dotnet run AsciiArt.cs di nuovo. Questa volta, l'host determina che l'eseguibile dotnet è corrente ed esegue il file eseguibile senza compilarlo di nuovo. Non viene visualizzato alcun output di compilazione.
I passaggi precedenti illustrano che le app basate su file non sono file script. Si tratta di file di origine C# compilati usando un file di progetto generato in una cartella temporanea. Una delle righe di output visualizzate durante la compilazione del programma dovrebbe avere un aspetto simile al seguente (in Windows):
AsciiArt succeeded (7.3s) → AppData\Local\Temp\dotnet\runfile\AsciiArt-85c58ae0cd68371711f06f297fa0d7891d0de82afde04d8c64d5f910ddc04ddc\bin\debug\AsciiArt.dll
Nelle piattaforme Unix la cartella di output è simile alla seguente:
AsciiArt succeeded (7.3s) → Library/Application Support/dotnet/runfile/AsciiArt-85c58ae0cd68371711f06f297fa0d7891d0de82afde04d8c64d5f910ddc04ddc/bin/debug/AsciiArt.dll
L'output indica dove vengono inseriti i file temporanei e gli output di compilazione. In questa esercitazione, ogni volta che si modifica il file di origine, l'host dotnet aggiorna l'eseguibile prima dell'esecuzione.
Le app basate su file sono normali programmi C#. L'unica limitazione è che devono essere scritte in un unico file di origine. È possibile usare istruzioni di primo livello o un metodo classico Main come punto di ingresso. È possibile dichiarare qualsiasi tipo: classi, interfacce e struct. È possibile strutturare gli algoritmi in un programma basato su file come in qualsiasi programma C#. È anche possibile dichiarare più spazi dei nomi per organizzare il codice. Se si ritiene che un programma basato su file sia troppo grande per un singolo file, è possibile convertirlo in un programma basato su progetto e suddividere l'origine in più file. Le app basate su file sono un ottimo strumento di prototipazione. È possibile iniziare a sperimentare con un sovraccarico minimo per dimostrare concetti e algoritmi di compilazione.
Supporto di Unix shebang (#!)
Annotazioni
Il supporto per #! le direttive si applica solo alle piattaforme unix. Non esiste una direttiva simile per Windows per eseguire direttamente un programma C#. In Windows è necessario usare dotnet run nella riga di comando.
In unix è possibile eseguire direttamente le app basate su file, digitando il nome del file di origine nella riga di dotnet runcomando anziché . È necessario apportare due modifiche:
Impostare le autorizzazioni di esecuzione per il file di origine:
chmod +x AsciiArt.csAggiungere una direttiva shebang (
#!) come prima riga delAsciiArt.csfile:#!/usr/local/share/dotnet/dotnet run
Il percorso di dotnet può essere diverso in diverse installazioni unix. Usare il comando which dotnet per individuare l'host dotnet nel tuo ambiente.
In alternativa, è possibile usare #!/usr/bin/env dotnet per risolvere automaticamente il percorso dotnet dalla variabile di ambiente PATH:
#!/usr/bin/env dotnet
Dopo aver apportato queste due modifiche, è possibile eseguire il programma direttamente dalla riga di comando:
./AsciiArt.cs
Se si preferisce, è possibile rimuovere l'estensione in modo da poter digitare ./AsciiArt . È possibile aggiungere l'oggetto #! al file di origine anche se si usa Windows. La riga di comando di Windows non supporta #!, ma il compilatore C# consente tale direttiva nelle app basate su file in tutte le piattaforme.
Leggere gli argomenti della riga di comando
Scrivere ora tutti gli argomenti nella riga di comando nell'output.
Sostituire il contenuto corrente di
AsciiArt.cscon il codice seguente:if (args.Length > 0) { string message = string.Join(' ', args); Console.WriteLine(message); }È possibile eseguire questa versione digitando il comando seguente:
dotnet run AsciiArt.cs -- This is the command line.L'opzione
--indica che tutti gli argomenti di comando seguenti devono essere passati al programma AsciiArt. Gli argomentiThis is the command line.vengono passati come matrice di stringhe, dove ogni stringa è una parola:This,isthe,command, eline..
Questa versione illustra questi nuovi concetti:
- Gli argomenti della riga di comando vengono passati al programma usando la variabile
argspredefinita . Laargsvariabile è una matrice di stringhe:string[]. Se la lunghezza diargsè 0, significa che non sono stati forniti argomenti. In caso contrario, ogni parola nell'elenco di argomenti viene archiviata nella voce corrispondente nella matrice. - Il
string.Joinmetodo unisce più stringhe in una singola stringa, con il separatore specificato. In questo caso, il separatore è uno spazio singolo. - Console.WriteLine scrive la stringa nella console di output standard, seguita da una nuova riga.
Gestire l'input standard
Che gestisce correttamente gli argomenti della riga di comando. Aggiungere ora il codice per gestire la lettura dell'input dall'input standard (stdin) anziché dagli argomenti della riga di comando.
Aggiungere la clausola seguente
elseall'istruzioneifaggiunta nel codice precedente:else { while (Console.ReadLine() is string line && line.Length > 0) { Console.WriteLine(line); } }Il codice precedente legge l'input della console fino a quando non viene letta una riga vuota o un oggetto
null. Il Console.ReadLine metodo restituiscenullse il flusso di input viene chiuso digitando CTRL+C.Testare la lettura dell'input standard creando un nuovo file di testo nella stessa cartella. Denominare il file
input.txte aggiungere le righe seguenti:Hello from ... dotnet! You can create file-based apps in .NET 10 and C# 14 Have fun writing useful utilitiesMantenere le righe brevi in modo che vengano formattate correttamente quando si aggiunge la funzionalità per usare l'arte ASCII.
Eseguire di nuovo il programma.
Con bash:
cat input.txt | dotnet run AsciiArt.csIn alternativa, con PowerShell:
Get-Content input.txt | dotnet run AsciiArt.cs
Ora il programma può accettare argomenti della riga di comando o input standard.
Scrivere l'output ASCII Art
Aggiungere quindi un pacchetto che supporti l'arte ASCII , Colorful.Console. Per aggiungere un pacchetto a un programma basato su file, usare la #:package direttiva .
Aggiungere la direttiva seguente dopo la
#!direttiva nel file AsciiArt.cs:#:package Colorful.Console@1.2.15Importante
La versione
1.2.15è stata la versione più recente delColorful.Consolepacchetto quando questa esercitazione è stata aggiornata per l'ultima volta. Controllare la pagina NuGet del pacchetto per la versione più recente per assicurarsi di usare una versione del pacchetto con le correzioni di sicurezza più recenti.Modificare invece le righe che chiamano
Console.WriteLineper usare ilColorful.Console.WriteAsciimetodo :async Task WriteAsciiArt(AsciiMessageOptions options) { foreach (string message in options.Messages) { Colorful.Console.WriteAscii(message); await Task.Delay(options.Delay); } }Eseguire il programma e viene visualizzato l'output dell'arte ASCII anziché il testo eco.
Opzioni dei comandi del processo
Aggiungere quindi l'analisi della riga di comando. La versione corrente scrive ogni parola come riga di output diversa. Gli argomenti della riga di comando aggiunti supportano due funzionalità:
Virgolette più parole che devono essere scritte su una riga:
AsciiArt.cs "This is line one" "This is another line" "This is the last line"Aggiungere un'opzione
--delayper sospendere tra ogni riga:AsciiArt.cs --delay 1000
Gli utenti devono essere in grado di usare entrambi gli argomenti insieme.
La maggior parte delle applicazioni della riga di comando deve analizzare gli argomenti della riga di comando per gestire in modo efficace opzioni, comandi e input utente. La System.CommandLine libreria offre funzionalità complete per gestire comandi, sottocomandi, opzioni e argomenti, consentendo di concentrarsi sulle operazioni eseguite dall'applicazione anziché sui meccanismi di analisi dell'input della riga di comando.
La System.CommandLine libreria offre diversi vantaggi principali:
- Generazione e convalida automatica del testo della Guida.
- Supporto per le convenzioni della riga di comando POSIX e Windows.
- Funzionalità di completamento delle schede predefinite.
- Comportamento di analisi coerente tra applicazioni.
Aggiungere il
System.CommandLinepacchetto. Aggiungere questa direttiva dopo la direttiva del pacchetto esistente:#:package System.CommandLine@2.0.0Importante
La versione
2.0.0è stata la versione più recente dell'ultimo aggiornamento dell'esercitazione. Se è disponibile una versione più recente, usare la versione più recente per assicurarsi di avere i pacchetti di sicurezza più recenti. Controllare la pagina NuGet del pacchetto per la versione più recente per assicurarsi di usare una versione del pacchetto con le correzioni di sicurezza più recenti.Aggiungere le istruzioni using necessarie all'inizio del file (dopo le
#!direttive e#:package):using System.CommandLine; using System.CommandLine.Parsing;Definire l'opzione di ritardo e l'argomento messaggi. Aggiungere il codice seguente per creare gli
CommandLine.Optionoggetti eCommandLine.Argumentper rappresentare l'opzione e l'argomento della riga di comando:Option<int> delayOption = new("--delay") { Description = "Delay between lines, specified as milliseconds.", DefaultValueFactory = parseResult => 100 }; Argument<string[]> messagesArgument = new("Messages") { Description = "Text to render." };Nelle applicazioni della riga di comando le opzioni in genere iniziano con
--(trattino doppio) e possono accettare argomenti. L'opzione--delayaccetta un argomento integer che specifica il ritardo in millisecondi.messagesArgumentdefinisce il modo in cui tutti i token rimanenti dopo le opzioni vengono analizzati come testo. Ogni token diventa una stringa separata nella matrice, ma il testo può essere racchiuso tra virgolette per includere più parole in un token. Ad esempio,"This is one message"diventa un singolo token, mentreThis is four tokensdiventa quattro token separati.Il codice precedente definisce il tipo di argomento per l'opzione
--delaye che gli argomenti sono una matrice distringvalori. Questa applicazione ha un solo comando, quindi si usa il comando radice.Creare un comando radice e configurarlo con l'opzione e l'argomento . Aggiungere l'argomento e l'opzione al comando radice:
RootCommand rootCommand = new("Ascii Art file-based program sample"); rootCommand.Options.Add(delayOption); rootCommand.Arguments.Add(messagesArgument);Aggiungere il codice per analizzare gli argomenti della riga di comando e gestire eventuali errori. Questo codice convalida gli argomenti della riga di comando e archivia gli argomenti analizzati nell'oggetto System.CommandLine.ParseResult :
ParseResult result = rootCommand.Parse(args); foreach (ParseError parseError in result.Errors) { Console.Error.WriteLine(parseError.Message); } if (result.Errors.Count > 0) { return 1; }
Il codice precedente convalida tutti gli argomenti della riga di comando. Se la convalida ha esito negativo, gli errori vengono scritti nella console e l'app viene chiusa.
Usare i risultati della riga di comando analizzati
Completare ora l'app per usare le opzioni analizzate e scrivere l'output. Definire prima di tutto un record per contenere le opzioni analizzate. Le app basate su file possono includere dichiarazioni di tipo, ad esempio record e classi. Devono essere dopo tutte le istruzioni di primo livello e le funzioni locali.
Aggiungere una
recorddichiarazione per archiviare i messaggi e il valore dell'opzione delay:public record AsciiMessageOptions(string[] Messages, int Delay);Aggiungere la funzione locale seguente prima della dichiarazione di record. Questo metodo gestisce sia gli argomenti della riga di comando che l'input standard e restituisce una nuova istanza del record:
async Task<AsciiMessageOptions> ProcessParseResults(ParseResult result) { int delay = result.GetValue(delayOption); List<string> messages = [.. result.GetValue(messagesArgument) ?? Array.Empty<string>()]; if (messages.Count == 0) { while (Console.ReadLine() is string line && line.Length > 0) { Colorful.Console.WriteAscii(line); await Task.Delay(delay); } } return new([.. messages], delay); }Creare una funzione locale per scrivere l'arte ASCII con il ritardo specificato. Questa funzione scrive ogni messaggio nel record con il ritardo specificato tra ogni messaggio:
async Task WriteAsciiArt(AsciiMessageOptions options) { foreach (string message in options.Messages) { Colorful.Console.WriteAscii(message); await Task.Delay(options.Delay); } }Sostituire la
ifclausola scritta in precedenza con il codice seguente che elabora gli argomenti della riga di comando e scrivere l'output:var parsedArgs = await ProcessParseResults(result); await WriteAsciiArt(parsedArgs); return 0;
È stato creato un record tipo che fornisce struttura alle opzioni e agli argomenti della riga di comando analizzati. Le nuove funzioni locali creano un'istanza del record e usano il record per scrivere l'output dell'arte ASCII.
Testare l'applicazione finale
Testare l'applicazione eseguendo diversi comandi. In caso di problemi, ecco l'esempio completato da confrontare con quello creato:
#!/usr/local/share/dotnet/dotnet run
#:package Colorful.Console@1.2.15
#:package System.CommandLine@2.0.0
using System.CommandLine;
using System.CommandLine.Parsing;
Option<int> delayOption = new("--delay")
{
Description = "Delay between lines, specified as milliseconds.",
DefaultValueFactory = parseResult => 100
};
Argument<string[]> messagesArgument = new("Messages")
{
Description = "Text to render."
};
RootCommand rootCommand = new("Ascii Art file-based program sample");
rootCommand.Options.Add(delayOption);
rootCommand.Arguments.Add(messagesArgument);
ParseResult result = rootCommand.Parse(args);
foreach (ParseError parseError in result.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
if (result.Errors.Count > 0)
{
return 1;
}
var parsedArgs = await ProcessParseResults(result);
await WriteAsciiArt(parsedArgs);
return 0;
async Task<AsciiMessageOptions> ProcessParseResults(ParseResult result)
{
int delay = result.GetValue(delayOption);
List<string> messages = [.. result.GetValue(messagesArgument) ?? Array.Empty<string>()];
if (messages.Count == 0)
{
while (Console.ReadLine() is string line && line.Length > 0)
{
// <WriteAscii>
Colorful.Console.WriteAscii(line);
// </WriteAscii>
await Task.Delay(delay);
}
}
return new([.. messages], delay);
}
async Task WriteAsciiArt(AsciiMessageOptions options)
{
foreach (string message in options.Messages)
{
Colorful.Console.WriteAscii(message);
await Task.Delay(options.Delay);
}
}
public record AsciiMessageOptions(string[] Messages, int Delay);
In questa esercitazione si è appreso come creare un programma basato su file, in cui si compila il programma in un singolo file C#. Questi programmi non usano un file di progetto e possono usare la #! direttiva nei sistemi Unix. Gli studenti possono creare questi programmi dopo aver provato le esercitazioni online e prima di creare app basate su progetti più grandi. Le app basate su file sono anche un'ottima piattaforma per le utilità della riga di comando.