絶対的な結論
フォームをジェネリッククラスにすることはやめた方がいい。
理由は下記の通り。
- フォームにリソースファイルがあるとビルドエラーになる。
- .NET8+ の環境だと Form1 すらフォームデザイナーを開けなくなる。
開発時の環境に制約が出たり煩わしくなるのと、.NET移行が確実に悪くなるから、やっぱりやらない方が吉っぽいです。
当初の調べた結果
.NET Framework 4.8.1 WinFormsで、ジェネリックの型が確定しているフォームなら、リビルドすればフォームデザイナーで開くことができた。
圧倒的にフォームデザイナーで開くことができないのは、ジェネリックの引数が確定していないフォームを開こうとしたときである。
リビルドすればいいんじゃね?
なんでできないっていう結論付けられたんだっけ???
経緯
プログラムを作っていて、確かそういうことできないよなあーと思って試しに書いたら出来ちゃったんですよ。
あれ?って思って調べたら、やっぱり下記のような情報が出てきて、回避策も昔から言われている方法。
そして私もその認識だった。
でも出来ちゃったから検証してみた。
ここで紹介されている InheritForm 自体も、結局リビルドしないと開けないし、あれ?ってなった。
Visual Studio 2022 からできるようになったのかと思ったけど、2017, 2019 でも出来たんだよねー。
できないシーンが分からなくなっちゃった。
検証したコード
using System.Windows.Forms;
namespace GenericFormTest
{
public partial class Form1<T> : Form where T : class, new()
{
public T Hoge { get; }
public Form1()
{
InitializeComponent();
Hoge = new T();
}
}
}
using System.Windows.Forms;
namespace GenericFormTest
{
public class Form2<T> : Form1<T> where T : class, new()
{
public Form2()
{
}
}
}
namespace GenericFormTest
{
public partial class Form3 : Form2<Class1>
{
public Form3()
{
InitializeComponent();
}
}
}
namespace GenericFormTest
{
public class Class1
{
}
}
コードの結果
Form1、Form3 は、通常のフォーム作成によってDesignerファイルも用意されているが、
Form2 に関しては、名前こそ Form2 だけど、クラス作成で用意していて、Designerファイルはない。
理由は、リビルドしたときにフォームデザイナーで表示できるかどうかが異なるから。
| クラス | フォームデザイナー |
|---|---|
| Form1 | 表示できる |
| Form2 | 表示できない |
| Form3 | 表示できる |
そのため、Form2 はDesignerファイルを持つ必要がなくて、あくまで Form2 では、ジェネリックの引数について更なる制御をするためだけに留める形になる。
ダブルクリックするとフォームデザイナーが開かれちゃうから、そこはトレードオフかな。
だから、Form2 が下記のようなコードになっても全然通用する。
namespace GenericFormTest
{
public class Form2<T1, T2> : Form1<T1> where T1 : class, new() where T2 : class, new()
{
public T2 Fuga { get; }
public Form2()
{
Fuga = new T2();
}
}
}