C#泛型类使用引用类型和可空值类型

时间:2011-09-20 18:38:11

标签: c# generics reflection

我有一个有趣的问题。我想创建一个可以处理Reference类型和Nullable<T>类型的泛型类。基本上我想要这样的东西:

public class ClassWithNull<T>
{
    public T varName = null;
}

现在,这当然不会编译,因为并非所有类型都可以赋值为null,即不可为空的值类型。但问题是Nullable<T>是一种值类型,因此简单地添加where T : class对我没有帮助。我的泛型foo不是太强,但是我无法找到任何方式来说T必须是引用类型或可以为值的值类型。

我必须解决的问题是使ClassWithNull<T>成为一个抽象类。然后我可以添加两个子类,一个用于处理引用类型,另一个用于处理可空值类型。然后,基类中的静态工厂方法可以使用反射来确定应该构造哪个子类。类似的东西:

public static ClassWithNull<T> CreateClassWithNull<T>()
{
    StackTrace st = new StackTrace();
    Type type = st.GetFrame(1).GetMethod().GetGenericArguments()[0];
    if (!type.IsValueType)
    {
        return new ClassWithReferenceType<T>();
    }
    else if (type == typeof(Nullable))
    {
        return new ClassWithNullableValueType<T>();
    }
    else
    {
        throw new Exception("Must provide nullable type.");
    }
}

这里的问题是泛型是静态解决的。如果ClassWithReferenceType<U>期望U成为引用类型,则在工厂方法中调用new ClassWithReferenceType<T>()是编译错误,因为T不需要是引用类型。编译器不知道运行时检查。

关于如何实现这样的事情的任何想法?

2 个答案:

答案 0 :(得分:5)

怎么样:

public class ClassWithNull<T>
{
    public T varName = default(T);
}

(实际上,你甚至不需要这个任务 - 你可以把它作为构造的默认值。但你可能想要default(T)用于局部变量。)

这不会阻止您使用不可为空的值类型错误地使用它 - 但这还够吗?

如果这对您没有帮助,我建议您编写两个静态方法,如下所示:

public static ClassWithNull<T> CreateClassWithNullForClass<T> where T : class
{
    return new ClassWithReferenceType<T>();
}

public static ClassWithNull<T> CreateClassWithNullForNullable<T> where T : struct
{
    return new ClassWithNullableValueType<T>();
}

ClassWithNullableValueType中的字段为Nullable<T> - T将是基础类型。

现在,如果你想要相同方法的重载,那就更难了,特别是如果你不想传递任何参数。这是可能的,但是really, really horrible

答案 1 :(得分:0)

您应该能够这样做:

public class ClassWithNull<T>
{
    private object varName_priv = null;

    public T varName {
        get { return (T)varName_priv; }
        set { varName_priv = value; }
    }
}

这是有效的,因为C#中的每个非指针类型都可以转换为object,包括值类型。