我有一个有趣的问题。我想创建一个泛型类,可以处理引用类型以及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
不需要是引用类型。编译器不知道运行时检查
关于如何实现这样的事情有什么想法吗?
如何:
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
将是底层类型。
您应该可以这样做:
public class ClassWithNull<T>
{
private object varName_priv = null;
public T varName {
get { return (T)varName_priv; }
set { varName_priv = value; }
}
}
这是有效的,因为c#中的所有非指针类型都可以转换为object
,包括值类型。