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

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

 public class ClassWithNull { public T varName = null; } 

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

我必须解决的想法是使ClassWithNull成为一个抽象类。 然后我可以添加两个子类,一个用于处理引用类型,另一个用于处理可空值类型。 然后,基类中的静态工厂方法可以使用reflection来确定应该构造哪个子类。 就像是:

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

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

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

怎么样:

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

(实际上,你甚至不需要赋值 – 你可以将它保留为构造的默认值。但你可能想要局部变量的default(T) 。)

这不会阻止您使用不可为空的值类型错误地使用它 – 但这样就足够了吗?

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

 public static ClassWithNull CreateClassWithNullForClass where T : class { return new ClassWithReferenceType(); } public static ClassWithNull CreateClassWithNullForNullable where T : struct { return new ClassWithNullableValueType(); } 

ClassWithNullableValueType的字段将为NullableT将是基础类型。

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

您应该能够这样做:

 public class ClassWithNull { private object varName_priv = null; public T varName { get { return (T)varName_priv; } set { varName_priv = value; } } } 

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