【发布时间】:2014-01-19 22:01:27
【问题描述】:
我有一个有趣的问题。我想创建一个可以处理引用类型和Nullable<T> 类型的泛型类。基本上我想要这样的东西:
public class ClassWithNull<T>
{
public T varName = null;
}
现在这当然不能编译,因为并非所有类型都可以赋值为 null,即不可为 null 的值类型。但问题是Nullable<T> 是一个值类型,所以简单地添加where T : class 对我没有帮助。我的 generics-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 不需要是引用类型。编译器不知道运行时检查。
关于如何实现这样的事情有什么想法吗?
【问题讨论】:
-
请注意,
T x = null;只会在x可以为空的情况下编译,但T x = default(T)和x == null将总是编译(对于非可空类型)。 -
在您的代码中,
typeof(Nullable)指的是另一种类型,而不是您想象的类型,即非泛型的静态类。相反,可以说type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)。在这种特定情况下,另一种选择是Nullable.GetUnderlyingType(type) != null。此外,您似乎可以使用typeof(T)而不是您所谓的type。
标签: c# generics reflection