对此问题的跟进:Why is Nullable<T> considered a struct and not a class?
我有两个类,基本上维护一个用户提供的值的元组和内部对象。
当用户提供的值的类型是基元时,我必须将其包装在Nullable<T>
中,以便它可以在元组中采用空值。
public class BundledClass<T> where T : class
{
private Tuple<T, object> _bundle;
public T Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
//...
public class BundledPrimitive<T> where T : struct
{
private Tuple<T?, object> _bundle;
public T? Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T?, object>(value, internalObj); }
}
//...
如果我能用一个可以将基元或类作为类型参数的类来做这个,我更喜欢它,但我没有看到任何解决方法。并非没有提出某种类型的自定义Nullable
类,它可以包装任何类型(不仅仅是类型where T:struct
),以确保始终可以为Value
分配null;
似乎我至少应该能够将后一类定义为
public class BundledPrimitive<T> : BundledClass<T?> { }
但即便失败,因为Nullable<T>
不符合: class
约束(根据链接问题)。
答案 0 :(得分:5)
如果您只是按照以下方式设计您的课程:
public abstract class Bundled<T>
{
private Tuple<T, object> _bundle;
public T Value
{
get { return _bundle == null ? default(T) : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
}
然后,您可以通过将类型参数指定为Nullable<T>
来将其与结构一起使用,例如:
Bundled<string> foo; // handles classes
Bundled<float?> bar; // handles structs
这里唯一的问题是,用户可以将此类与不可为空的结构一起使用 - 例如。 Bundled<int>
。如果您的应用程序确实存在问题,您可以声明更具体的子类型,如下所示:
public class BundledClass<T> : Bundled<T> where T : class { }
public class BundledStruct<T> : Bundled<T?> where T : struct { }
您也可以为Bundled<T>
内部构建一个构造函数,这样就无法从程序集外部调用它。这将确保用户不会创建自定义子类型以绕过您的BundledClass
/ BundledStruct
包装。
答案 1 :(得分:2)
我现在能想到的最好的。它仍然是两个类,但它使我免于数百行代码重复:
public abstract class Bundled<T>
{
protected Tuple<T, object> _bundle;
public abstract T Value { get; set; }
//... Everything else
}
public class BundledClass<T> : Bundled<T> where T : class
{
public sealed override T Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T, object>(value, internalObj); }
}
}
public class BundledPrimitive<T> : Bundled<T?> where T : struct
{
public sealed override T? Value
{
get { return _bundle == null ? null : _bundle.Item1; }
set { _bundle = new Tuple<T?, object>(value, internalObj); }
}
}