C# 在泛型中使用什么类型的装箱

C# 在泛型中使用什么类型的装箱,c#,generics,.net-2.0,struct,C#,Generics,.net 2.0,Struct,我已经用C#(.NET2.0)编写了一个简单的抽象泛型类,我最好将它限制为仅引用类型,这样我就可以用null表示没有值。但是,我也希望使用long和decimal等类型,为什么不允许null(毕竟是结构体)。我考虑去上课 public abstract Field<Nullable<T>> { } 公共摘要字段 { } 但这会阻止我使用字符串类型,它是一个类。我怎样才能把小数和长数框起来,这样我就可以在这个泛型中使用它们了 abstract class Field

我已经用C#(.NET2.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;
        }
    }

}
抽象类字段
{
私有整数长度=1;
私有bool_Required=false;
受保护的T_值;//=null;
公共整数长度
{
获取{return_Length;}
专用设备
{
如果(值<1)抛出新的ArgumentException(“字段长度必须至少为1”);
_长度=值;
}
}
公共图书馆
{
获取{return\u Required;}
私有集{u Required=value;}
}
公共抽象字符串GetFieldValue();
公共抽象字段值(字符串s);
公共虚拟T值
{
获取{返回_值;}
设置
{
if(值==null&&Required)
抛出新ArgumentException(“必需的值不能为null”);
_价值=价值;
}
}
}
请注意,我需要以不同的方式表示数字0和null。因此,默认设置(T)将不起作用。

请尝试以下操作:

public abstract Field<T>
    where T : class
{

}
公共摘要字段
T:在哪里上课
{
}

这将限制泛型类型参数为引用类型。这是从该方法返回
null
的唯一方法。是的,这将阻止您将值类型传递给方法。

泛型(以及其他)的全部要点是避免装箱。见:

如果您需要区分“0”和“未设置”,则
对象
是您唯一的出路:

protected object _Value;

然后用盒子拆开盒子拆开盒子。

这是个好问题。我希望这是可能的:

class MyClass<T> where T : struct {
    T? value;
    ...
}
class MyClass<T> where T : class {
    T value;
    ...
}
classmyclass,其中T:struct{
T值;
...
}
类MyClass,其中T:class{
T值;
...
}
编译器将根据是否满足约束选择正确的泛型类


不幸的是,它无法工作,这可能会导致自动源代码生成出现问题。

您需要两个类

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>
Nullable

我不确定是否可以在编译时适当地约束泛型参数,但可以添加一些运行时检查,只允许引用类型以及所需的可空值类型子集:

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;
    }
}
公共虚拟T值
{
获取{返回_值;}
设置
{
类型t=类型(t);
if(t.IsValueType)
{
if(t.IsGenericType
&&(t.GetGenericTypeDefinition()==typeof(可空)))
{
类型u=可空。GetUnderlineType(t);
if((u!=typeof(long))&&(u!=typeof(decimal)))
{
抛出新的ArgumentException(
“只允许长字符和小数字符!”;
}
}
其他的
{
抛出新ArgumentException(“仅允许为null的类型!”);
}
}
if((值==null)和&Required)
{
抛出新ArgumentException(“必需的值不能为null!”);
}
_价值=价值;
}
}

(实际上,您可能希望将类型检查放在构造函数中,而不是放在
值设置器中。)

我建议您创建一个带有无约束类型参数T的类持有者,它公开类型为T的字段;它既有一个默认构造函数,也有一个T类型的单参数构造函数。此外,您可能需要定义一个接口IReadableHolder,它将由Holder实现,但也可以由您定义的任何类类型实现(类Foo的实例将通过其Value属性返回自身来实现IReadableHolder,从而允许例程期望IReadableHolder接受Holder或Foo本身。太糟糕了,无法定义“扩展接口”将IHolder的实现添加到类字符串。

这将不允许使用长或小数,正如问题中特别说明的那样。请在发布之前阅读。@C.Ross-我在发布之前阅读过。如果您重新阅读我的答案,您会注意到我指出,从返回值的泛型方法返回null的唯一方法是这就是其中一个泛型参数的类型,即用“class”约束该参数。这是一个很好的答案,但不幸的是,我需要分别表示0和“No value”。如果这两个参数都是从一个共同的非泛型祖先(字段)派生而来,那么这实际上可能会起作用…@C.Ross-是的,这可能很有效。我以前使用过非泛型基类来支持继承的分支。
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;
    }
}