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

jjo*_*son 3 c# generics reflection

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

public class ClassWithNull<T>
{
    public T varName = null;
}
Run Code Online (Sandbox Code Playgroud)

当然,这当然不会编译,因为并非所有类型都可以赋值为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.");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*eet 5

怎么样:

public class ClassWithNull<T>
{
    public T varName = default(T);
}
Run Code Online (Sandbox Code Playgroud)

(实际上,你甚至不需要赋值 - 你可以将它保留为构造的默认值.但你可能想要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>();
}
Run Code Online (Sandbox Code Playgroud)

该字段ClassWithNullableValueType将是Nullable<T>- T将是基础类型.

现在,如果你想要相同方法的重载,那就会变得更难,特别是如果你不想传递任何参数.这是可能的,但实际上,真的非常可怕.