72039


最近VS Codeを使ってC#のプログラミングの勉強を始めました。

そこで質問なのですが、簡単なプログラムをいくつも作って単体で動かす練習をしたい場合に、現在の環境ではメインメソッドを備えたクラスを複数作ることが許されません。

私としては、Javaのように1つのパッケージにメインメソッドを含んだクラスがたくさん連続して作成できたらいいのになと思うのですが、C#ではそれは叶わないのでしょうか。

例えばハローワールドのプログラムを1つ作っちゃったら、次にFizzBuzzを書いて動かすにはハローワールドを削除して…ってめんどくさすぎやしませんか。

基本的な文法などを学びたいだけなのに大変過ぎます。

あるいは、Visual Studioなら可能ですか。軽さが好きなのでできればVS Codeでいきたいのですが。

皆さんどうされてますか。よろしくお願いいたします。


CC BY-SA 4.0
2020-11-17T17:13:18.340
72018
2020-11-18T14:32:51.013
question
c# vscode
C#の開発環境について


出来ると言えば出来るでしょう。

以下のエラーが発生していると思われますが、Visual Studioでも同じことをすれば同じようにエラーとなります。  
[コンパイラ エラー CS0017](https://docs.microsoft.com/ja-jp/dotnet/csharp/misc/cs0017)

> プログラム 'output file name' に、複数のエントリ ポイントが定義されています。 エントリ
> ポイントを含む型を指定するために、/main を使用してコンパイルします。  
>  プログラムには、 Main メソッドを 1 つのみ指定できます。  
>  このエラーを解決するには、コード内のすべての Main メソッドを削除するか、または -main コンパイラオプションを使用して、使用する main
> メソッドを指定します。

しかし説明にある通り、-main コンパイラオプションを使用して明示的に指定すればビルド出来ます。  
[-main (C# コンパイラ オプション)](https://docs.microsoft.com/ja-
jp/dotnet/csharp/language-reference/compiler-options/main-compiler-option)

Visual Studio Codeならば、以下のいずれかの方法(ビルド時のコマンドラインオプションを指定するか、.csproj
ファイルを手動で編集して指定)が使えると思われます。  
[例](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-
reference/compiler-options/main-compiler-option#example)

> **Main** メソッドが`Test2`にあることを指定して、`t2.cs`と`t3.cs`をコンパイルします。
[code]

>     csc t2.cs t3.cs -main:Test2
>  
[/code]

[.csproj ファイルを手動で編集してこのコンパイラ オプションを設定するには](https://docs.microsoft.com/ja-
jp/dotnet/csharp/language-reference/compiler-options/main-compiler-option#to-
set-this-compiler-option-by-manually-editing-the-csproj-file)

> .csproj
> ファイルを編集し、`PropertyGroup`セクション内に`StartupObject`要素を追加することで、このオプションを設定できます。
> 次に例を示します。
[code]

>       <PropertyGroup>
>         ...
>         <StartupObject>MyApplication.Core.Program</StartupObject>
>       </PropertyGroup>
>  
[/code]

* * *

ただしわざわざ1つのソリューション/プロジェクトを使い回すそんな方法で複数のプログラムを作成したりはしないですね。  
作るプログラム毎に新規にソリューション/プロジェクトを作成するのが普通です。

> 例えばハローワールドのプログラムを1つ作っちゃったら、次にFizzBuzzを書いて動かすにはハローワールドを削除して…ってめんどくさすぎやしませんか。

* * *

ちなみに、ソリューション/プロジェクトのフォルダが一杯出来てゴチャゴチャしてしまうのが嫌だという考えもあり、それも分からなくは無いので、改善案としてはソリューションを1つにして、その下にプロジェクトを複数(ハローワールドプロジェクトとかFizzBuzzプロジェクト等)作るようにすれば良いでしょう。  
(@radian さんもそういう回答を書いていますが)

Visual
Studioならば、ソリューションエクスプローラーで対象プロジェクトを右クリックして「スタートアッププロジェクトに設定」すれば切り替えることが出来ます。

Visual Studio Codeでも同様のことが出来るのではないでしょうか？  
[複数のプロジェクトを設定する](https://sodocumentation.net/ja/vscode/topic/7717/%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)

説明の趣旨は少し違いますが、こんな方法でプロジェクトを複数作って切り替えられるでしょう。  
[ソリューションの構造](https://sodocumentation.net/ja/vscode/topic/7717/%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B#----------)

>
> テストプロジェクトを/testフォルダの下に置き、ソースプロジェクトを/srcフォルダの下に置くなど、プロジェクトをグループ化することは非常に一般的です。
> global.jsonファイルを追加して同様の構造にします：

こちらも趣旨は違って、連携する複数のプロジェクトを同時に動かしてデバッグするには？という質問ですが、1ソリューション/複数プロジェクトの環境設定としては同様でしょう。  
[Debugging in vscode with multiple dotnet core projects under one
solution](https://stackoverflow.com/q/37376415/9014308)  
[Running two projects at once in Visual Studio
Code](https://stackoverflow.com/q/38529937/9014308)


CC BY-SA 4.0
2020-11-17T22:54:59.657
72019
2020-11-18T02:25:30.987
2020-11-18T02:25:30.987
26370
26370
72018
answer


>
> そこで質問なのですが、簡単なプログラムをいくつも作って単体で動かす練習をしたい場合に、現在の環境ではメインメソッドを備えたクラスを複数作ることが許されません。

VSCodeは知りませんが、Visual
Studioなら、コンパイル対象のファイル以外をソリューションエクスプローラーから右クリックして「プロジェクトから除外」しておくだけで済みます。  
戻す場合は、除外したファイルが非表示になっているなら「全てのファイルを表示を選択」アイコンを選択し、ファイルを選択して右クリックして「プロジェクトに含める」で戻せます。

もしくは、プロジェクトのプロパティでスタートアップオブジェクトを指定すれば、切り替えは可能です。  
[![プロジェクトのプロパティ](https://i.stack.imgur.com/n38x0.png)](https://i.stack.imgur.com/n38x0.png)

ただ、Main含む1ソースだけで済むならいいのですが、参照するアセンブリが違ったり、複数のソースを使用していたり、プロジェクトの種類が違うと面倒になるので、基本的には私の場合はプロジェクトを新規で作りますね。


CC BY-SA 4.0
2020-11-18T01:42:24.123
72021
2020-11-18T02:19:45.447
2020-11-18T02:19:45.447
41943
41943
72018
answer


### 実行時引数にクラス名を指定して起動する

実行時引数にクラス名を指定して起動する、ということを実現するコードを書いてみました。  
対象のクラスに`ClassMain`という名前のメソッドを実装しておけばクラス名から呼び出せる仕組みです。

[code]

    using System;
    using System.Linq;
    
    namespace SampleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                CallClassMain(args);
            }
    
            static void CallClassMain(string[] args)
            {
                try
                {
                    if (args.Length < 1) throw new ArgumentException("Requires startup class name");
                    var className = nameof(SampleApp) + "." + args[0];
                    var arguments = args.Skip(1).ToArray();
                    var type = Type.GetType(className);
                    if (type is null) throw new ArgumentException($"No such class: {className}");
                    type.InvokeMember("ClassMain", System.Reflection.BindingFlags.InvokeMethod, null, null, new object[] { arguments });
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error: {ex.Message}");
                }
            }
        }
    
        public class Sample1
        {
            public static void ClassMain(string[] args)
            {
                Console.WriteLine("Hello, Sample1");
            }
        }
    
        public class Sample2
        {
            public static void ClassMain(string[] args)
            {
                Console.WriteLine("Hello, Sample2");
            }
        }
    }
    
[/code]

使い方はこんな感じです。

[code]

    > SampleApp.exe Sample1
    Hello, Sample1
    
[/code]

* * *

### コメントアウトで切り替える

自分としては以下のようなコメントアウトで自分で切り替えるのがシンプルで一番わかりやすいです。

[code]

    static void Main(string[] args)
    {
        Sample1.ClassMain(args);
        //Sample2.ClassMain(args);
    }
    
[/code]


CC BY-SA 4.0
2020-11-18T14:32:51.013
72039
2020-11-18T14:32:51.013
14817
72018
answer