我应该如何处理关于C#8.0中的nullable选项的泛型问题?
c#
最近我有,如果通用类型是一个类或结构,详细之间的麻烦,当我宣布T有既不限制class也不是struct,也是#nullable选项启用,则泛型类型得到一些意外行为。例如,如果我用该类型构造一个成员T?并T指定为不可为空的结构类型,则该T?类型不会作为可空结构进行操作。这是一个关于它的解释代码:
public class MyClass<T> {
...
public MyClass (T value, T? another) { ... }
public void DoExample () {
MyClass<int> a = new MyClass<int>(1, null); /* causes the CS1503 error, indicating int cannot receive null.
In other words, T? is still int, not the nullable int.*/
}
}
我应该怎么做才能解决这个问题?
也许解决了
最后,我找到了一个不完整但非常合理的解决方案来解决它。以下内容将帮助我们解决问题。
public class NullableWrapper<T> where T : notnull /* this constraint is not necessary
but if you want every type that specifies T to be non-nullable
and/or would not like to consider the null reference exception which may arise at Equals,
GetHashCode, and ToString, that would modify the type accuracy and/or your need. */ {
public T Value { get; set; } = default!;
internal NullableWrapper (T value) => this.Value = value;
public override bool Equals (object? obj) => this.Value.Equals(obj);
public override int GetHashCode () => this.Value.GetHashCode();
public override string? ToString () => $"NullableWrapper({this.Value})";
public static implicit operator NullableWrapper<T> (T itself)
=> new NullableWrapper<T>(itself);
public static implicit operator T (NullableWrapper<T> itself)
=> itself.Value;
}
然后,我之前的代码更改为如下所示:
public class MyClass<T> where T : notnull {
...
public MyClass (T value, NullableWrapper<T>? another) { ... }
public void DoExample () {
MyClass<int> a = new MyClass<int>(1, null); // this causes none of error.
MyClass<string> b = new MyClass<string>("hello", null); // similarly, no error happens.
MyClass<double> c = new MyClass<double>(2.6, 5.2); // it's equivalent to the previous.
MyClass<string> d = new MyClass<string>("asd", "def"); // as well.
}
}
回答
- 可空引用类型仅在编译时存在:
Foo<string>并且Foo<string?>编译为相同的Foo<System.String>. - 可空值类型不同:
intisSystem.Int32、int?isSystem.Nullable<System.Int32>。
当您class MyClass<T> 没有 时 where T : struct,编译器默认为可空引用类型行为,其中int?没有真正意义,但仍被视为Int32,并且Nullable<Int32>不像您期望的那样,并且null不是 的有效值Int32。
从 .NET 5 / C# 9 开始,不可能有这样的泛型类型。它适用于class或struct,但不能同时适用于两者。
@insane_developer 提供了 LDM 会议的讨论链接:https :
//github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-11-25.md#problem-1-t- and-t-mean-不同的东西
问题1:T?和T?意思不同
第一个问题不是技术问题,而是感知和语言规律性问题。考虑:
public T? M1<T>(T t) where T : struct; public T? M2<T>(T t); var i1 = M1(7); // i1 is int? var i2 = M2(7); // i2 is int
M1今天的声明是合法的。因为T被约束为(T?不可为空的)值类型,所以被称为可以为空的值类型,因此,当用 实例化时int,返回类型是int?。的声明
M2是提议允许的内容。因为T是不受约束的,T?是“类型的default(T)”。当使用isint类型实例化时,这就是返回类型。default(int)int换句话说,对于相同的前提,
T这两个方法具有不同的返回类型,尽管唯一的区别是一个有约束T而另一个没有。这里的认知失调是我们不接受
T?不受约束的主要原因T。