私はこの問題に遭遇し、「null可能」なもの(参照型またはNull可能)をとることができる汎用の静的メソッドが必要だったため、満足のいく解決策がなかったため、この問題が発生しました。単純に2つのオーバーロードされたメソッド、かかる有するものでOPの規定の問題よりも解決することは比較的簡単だった私自身の解決策を考え出した私はそうT
と制約があるwhere T : class
かかり、別のT?
と持っているがwhere T : struct
。
次に、このソリューションをこの問題に適用して、コンストラクターをプライベート(または保護)にし、静的なファクトリメソッドを使用することで、コンパイル時にチェック可能なソリューションを作成できることにも気付きました。
//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);
}
}
これで、次のように使用できます。
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
パラメーターなしのコンストラクターが必要な場合は、オーバーロードの便利さは得られませんが、次のようなことができます。
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?>();
}
}
次のように使用します。
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
このソリューションにはいくつかの欠点があります。1つは、オブジェクトの構築に「新規」を使用することを好む場合があることです。もう1つは、次Foo<T>
のような型制約のジェネリック型引数として使用できないことですwhere TFoo: new()
。最後に、ここで必要な追加のコードが少しあります。これは、特に複数のオーバーロードされたコンストラクタが必要な場合に増加します。