我遇到了一个更简单的情况,即想要一个通用静态方法,该方法可以采用任何“可为空”(引用类型或可为空)的方法,这使我想到了这个问题,但没有令人满意的解决方案。因此,我想出了自己的解决方案,该解决方案比OP提出的问题要容易得多,因为它仅具有两个重载方法,一个重载方法具有a T
并具有约束where T : class
,另一个重载方法具有a 并具有T?
and具有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
该解决方案几乎没有缺点,一个缺点是您可能更喜欢使用“ new”构造对象。另一个原因是,你将无法使用Foo<T>
作为的类似类型约束泛型类型参数:where TFoo: new()
。最后是这里需要的一些额外代码,尤其是在需要多个重载的构造函数的情况下,这会增加。