我在C#(.NET 2.0)中编写了一个简单的抽象泛型类,我最好只想将它限制为只引用类型,所以我可以用null表示没有值。但是,我也想使用long和decimal等类型,为什么不允许null(毕竟是结构)。我考虑过上课
public abstract Field<Nullable<T>>
{
}
但这会阻止我使用字符串类型,这是一个类。如何将我的小数和长数加起来以便我可以在这个通用中使用它们。
abstract class Field<T>
{
private int _Length = 1;
private bool _Required = false;
protected T _Value; //= null;
public int Length
{
get { return _Length; }
private set
{
if (value < 1) throw new ArgumentException("Field length must be at least one.");
_Length = value;
}
}
public bool Required
{
get { return _Required; }
private set { _Required = value; }
}
public abstract string GetFieldValue();
public abstract void ParseFieldValue(string s);
public virtual T Value
{
get { return _Value; }
set
{
if (value == null && Required)
throw new ArgumentException("Required values cannot be null.");
_Value = value;
}
}
}
请注意,我需要以不同的方式表示数字0和null。因此,默认(T)将不起作用。
答案 0 :(得分:3)
仿制药(以及其他)的重点是避免拳击。见this:
private bool _Required = false;
protected T _Value = default(T);
如果您需要区分“0”和“未设置”,object
是您唯一的出路:
protected object _Value;
然后选择box-unbox-box-unbox。
答案 1 :(得分:2)
你需要两个班级
abstract class FieldR<T> where T: class
{
T Value { get {} set {} }
}
abstract class FieldV<T> where T: struct
{
Nullable<T> Value { get {} set {} }
}
第一堂课将使用
T
虽然第二节课会使用
Nullable<T>
答案 2 :(得分:1)
我不确定您是否可以在编译时适当地约束通用参数,但是您可以添加一些运行时检查以仅允许引用类型以及所需的可空值类型的子集:
public virtual T Value
{
get { return _Value; }
set
{
Type t = typeof(T);
if (t.IsValueType)
{
if (t.IsGenericType
&& (t.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
Type u = Nullable.GetUnderlyingType(t);
if ((u != typeof(long)) && (u != typeof(decimal)))
{
throw new ArgumentException(
"Only long? and decimal? permitted!");
}
}
else
{
throw new ArgumentException("Only nullable types permitted!");
}
}
if ((value == null) && Required)
{
throw new ArgumentException("Required values cannot be null!");
}
_Value = value;
}
}
(实际上,您可能希望将类型检查放在构造函数而不是Value
setter中。)
答案 3 :(得分:0)
试试这个:
public abstract Field<T>
where T : class
{
}
这会将泛型类型参数限制为引用类型。这是您能够从此方法返回null
的唯一方法。是的,这将阻止您将值类型传递给方法。
答案 4 :(得分:0)
这是一个很好的问题。我希望这是可能的:
class MyClass<T> where T : struct {
T? value;
...
}
class MyClass<T> where T : class {
T value;
...
}
并且编译器将根据是否满足约束来选择正确的泛型类。
不幸的是,它不起作用,这可能会导致自动生成源代码出现问题。
答案 5 :(得分:0)
我建议您创建一个类Holder&lt; T&gt;具有无约束的类型参数T,其暴露类型为T的字段;它将同时具有默认构造函数和类型为T的单参数构造函数。此外,您可能希望定义一个接口IReadableHolder&lt; T&gt;,它将由Holder&lt; T&gt;实现,但也可以由任何实现您定义的类类型(类Foo的实例将通过使其Value属性返回自身来实现IReadableHolder&lt; Foo&gt;因此允许例程期望IReadableHolder&lt; Foo&gt;接受Holder&lt; Foo&gt;或foo本身。太糟糕了无法定义“扩展接口”以将IHolder&lt; String&gt;的实现添加到类String。