我应该如何处理关于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>.
  • 可空值类型不同:intis System.Int32int?is System.Nullable<System.Int32>

当您class MyClass<T> 没有 时 where T : struct,编译器默认为可空引用类型行为,其中int?没有真正意义,但仍被视为Int32,并且Nullable<Int32>不像您期望的那样,并且null不是 的有效值Int32

从 .NET 5 / C# 9 开始,不可能有这样的泛型类型。它适用于classstruct,但不能同时适用于两者。

@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


以上是我应该如何处理关于C#8.0中的nullable选项的泛型问题?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>