我使用的是C#9,遇到了这个奇怪的问题,因此我在下面写了一个简单的示例来演示它。我需要将可为空的枚举的值设置为null,但是通过泛型类型执行此操作时会出现错误。如果我将枚举类型硬编码到类中,则可以正常工作,所以我不确定为什么将相同类型用作泛型时它不起作用。似乎TOption?
将其视为TOption
忽略了可为空的部分,这将使此错误变得有意义,因为它将尝试将null分配给不可为空的值类型。
这是可空类型,值类型和编译器假设之间的奇怪冲突吗?不应TOption?
与将Option?
whenOption
用作泛型类型时完全一样地对待吗?
请注意,TOption
在实际情况下,我不能约束为值类型来解决此问题,并且我认为此约束不是必需的。我不需要TOption
是值类型,我只需要该字段可为空即可-不管它是类还是结构。
关于放入Option?
for TOption
,我仍然需要将其视为不可为空的字段。因此,我无法做到这一点,我需要泛型中的实际类型,但我需要能够区分该类型的不可为null和可为null的字段-与作为结构或类的类型无关。我应该指出,我使用的是可为空的引用类型,因此除非使用进行了指定,否则将类视为不可为空?
。
public class Program
{
public static void Main(string[] args)
{
var test = new Test<Option>();
test.Option1 = null;
test.Option2 = null; // Cannot convert null to 'Program.Option' because it is a non-nullable value type
}
public enum Option { A, B, C }
public class Test<TOption>
{
public Option Option0 { get; set; }
public Option? Option1 { get; set; }
public TOption? Option2 { get; set; }
}
}
失败的原因与我在这里所作的解释非常相似。在这种情况下,有一种解决方法,但在您的情况下,您实际上需要一个可为空的值类型,这使得这几乎不可能。
T?
对CLR来说,意味着两个完全不同的内容T
。如果T
是值类型,则表示Nullable<T>
。如果T
是引用类型,就CLR而言,T?
实际上与T
(具有某些属性)相同。
因此,当编译器正在编译您的代码时,它将表示哪种类型Option2
?换句话说,如果您typeof(Test<>)
使用反射检查了(注意开放类型)的成员,那么Option2
属性的类型是什么?
在你的理想世界中,你想Option2
成为的类型Nullable<TOption>
时,TOption
是值类型,并且类型TOption
时TOption
是引用类型。但是,如果我们要检查的属性的typeof(Test<>)
类型,我们将得到哪种类型?不能两者都可以吗?
实际上,编译器选择TOption
的类型Option2
并将其类型视为Option2
可为空,但也要记住,它也可以是不可为空的值类型。
这就是为什么仅凭说就不可能实现“可空值和引用类型”的原因T?
。
一个相当丑陋的解决方法是创建自己的Nullable<T>
不限制T
值类型的方法:
struct MyNullable<T> where T: notnull {
private T value;
public bool HasValue {
get;
}
public T Value {
get {
if (HasValue) {
return value;
} else {
throw new InvalidOperationException("Value is not present!");
}
}
}
public MyNullable(T t) {
value = t;
HasValue = t != null;
}
}
现在您可以执行以下操作:
public class Test<TOption>
{
public Option Option0 { get; set; }
public Option? Option1 { get; set; }
public MyNullable<TOption> Option2 { get; set; }
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句