我遇到了这个问题,因为我想要一个可以接受任何“可为空”(引用类型或 Nullables)的通用静态方法的更简单的情况,这让我遇到了这个问题,但没有令人满意的解决方案。所以我想出了我自己的解决方案,它比 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
这个解决方案有几个缺点,一个是你可能更喜欢使用'new'来构造对象。另一个是您将无法使用Foo<T> 作为类型约束的泛型类型参数:where TFoo: new()。最后是您需要的一些额外代码,尤其是在您需要多个重载构造函数时。