Saya mengalami masalah ini untuk kasus sederhana yang menginginkan metode statis generik yang dapat mengambil apa pun "nullable" (baik jenis referensi atau Nullables), yang membawa saya ke pertanyaan ini tanpa solusi yang memuaskan. Jadi saya datang dengan solusi saya sendiri yang relatif lebih mudah untuk dipecahkan daripada pertanyaan yang dinyatakan OP dengan hanya memiliki dua metode kelebihan beban, satu yang mengambil T
dan memiliki kendala where T : class
dan yang lain yang mengambil T?
dan memiliki where T : struct
.
Saya kemudian menyadari, solusi itu juga dapat diterapkan pada masalah ini untuk membuat solusi yang dapat diperiksa pada waktu kompilasi dengan membuat konstruktor pribadi (atau dilindungi) dan menggunakan metode pabrik statis:
//this class is to avoid having to supply generic type arguments
//to the static factory call (see CA1000)
public static class Foo
{
public static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return Foo<TFoo>.Create(value);
}
public static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return Foo<TFoo?>.Create(value);
}
}
public class Foo<T>
{
private T item;
private Foo(T value)
{
item = value;
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return new Foo<TFoo>(value);
}
internal static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return new Foo<TFoo?>(value);
}
}
Sekarang kita bisa menggunakannya seperti ini:
var foo1 = new Foo<int>(1); //does not compile
var foo2 = Foo.Create(2); //does not compile
var foo3 = Foo.Create(""); //compiles
var foo4 = Foo.Create(new object()); //compiles
var foo5 = Foo.Create((int?)5); //compiles
Jika Anda menginginkan konstruktor tanpa parameter, Anda tidak akan mendapatkan kelebihan beban, tetapi Anda masih dapat melakukan sesuatu seperti ini:
public static class Foo
{
public static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return Foo<TFoo>.Create<TFoo>();
}
public static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return Foo<TFoo?>.CreateNullable<TFoo>();
}
}
public class Foo<T>
{
private T item;
private Foo()
{
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return new Foo<TFoo>();
}
internal static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return new Foo<TFoo?>();
}
}
Dan gunakan seperti ini:
var foo1 = new Foo<int>(); //does not compile
var foo2 = Foo.Create<int>(); //does not compile
var foo3 = Foo.Create<string>(); //compiles
var foo4 = Foo.Create<object>(); //compiles
var foo5 = Foo.CreateNullable<int>(); //compiles
Ada beberapa kelemahan dari solusi ini, salah satunya adalah Anda mungkin lebih suka menggunakan 'baru' untuk membuat objek. Lain adalah bahwa Anda tidak akan dapat menggunakan Foo<T>
sebagai jenis argumen generik untuk jenis kendala sesuatu seperti: where TFoo: new()
. Terakhir adalah sedikit kode tambahan yang Anda butuhkan di sini yang akan meningkat terutama jika Anda membutuhkan banyak konstruktor yang kelebihan beban.