简体   繁体   English

C#:泛型 T 的默认值? 不为空; 通用约束的行为改变

[英]C#: default of generic T? is not null; behavior changes with generic constraint

I have a generic class that should operate on (non-nullable) reference and value types (parameters, returns ...) but internally needs fields that can be null.我有一个通用类,它应该对(不可为空的)引用和值类型(参数、返回...)进行操作,但内部需要可以为空的字段。

using System;

public class Gen<T> // where T : struct
{
    public class Data
    {
        public T? t;
    }

    public static void Write(string s)
    {
        Data d = new Data();
        Console.WriteLine("Default of {0} is {1}", s, d.t == null ? "null" : "NOT null");
    }

    // ... other stuff that uses T and not T? like
    // public T DoSomething(T value) ...
}

static class Program
{
    static void Main(string[] args)
    {
        Gen<int>.Write("int?");
        Gen<string>.Write("string?");
    }
}

This code does not produce any errors or warnings when compiled (.NET 5) with nullable enabled.在启用可空值的情况下编译 (.NET 5) 时,此代码不会产生任何错误或警告。 However the behavior is not as I have expected.然而,行为并不像我预期的那样。

Default of int? is NOT null
Default of string? is null

While playing around searching for a solution, I discovered that when the where T : struct constraint is added (and Gen.Write() removed), the behavior changes to在寻找解决方案的过程中,我发现当添加where T : struct约束(并删除 Gen.Write())时,行为更改为

Default of int? is null

It's odd that a constraint changes the behavior.奇怪的是,约束会改变行为。

Does anybody know a elegant solution to write such a generic class?有人知道编写这样一个通用类的优雅解决方案吗? Using a custom Nullable class that supports reference types too or a separate bool flags for every T?使用也支持引用类型的自定义 Nullable 类还是为每个 T 使用单独的 bool 标志? filed is a bit tedious.归档有点乏味。

If you want to use Nullable<int> you shouldn't use int , so use:如果你想使用Nullable<int>你不应该使用int ,所以使用:

Gen<int?>.Write("int?");

Then the output will be然后输出将是

Default of int? is null
Default of string? is null

The code in the question is an example.问题中的代码是一个示例。 The real class does not have a Write method and never uses the string of the type.真正的类没有Write方法,也从不使用该类型的字符串。 However as I indicated by 'other stuff' it uses T as well as T?.然而,正如我通过“其他东西”所指出的,它使用 T 和 T?。 So it is not desired to instantiate it with int?所以不希望用int?实例化它int? instead of int .而不是int

First i want to explain why it's not odd that the struct constraint in the generic class changes the behavior.首先我想解释一下为什么泛型类中的struct约束改变行为并不奇怪。 Because actually that constraint makes it compile if you are < C#8.因为实际上,如果您是 < C#8,则该约束会使其编译。 Then T?那么T? means Nullable<T> , so if you use Gen<int>.Write("int?") the field t will be a Nullable<int> .表示Nullable<T> ,因此如果您使用Gen<int>.Write("int?")字段t将是Nullable<int> But then Gen<string>.Write("string") won't compile at all since string is not a struct .但是Gen<string>.Write("string")根本不会编译,因为string不是struct So it has a completely different meaning with the constraint.所以它与约束有完全不同的含义。

With C#8 enabled you can remove the struct constrained, then t remains an int and the string will be a nullable string .启用 C#8 后,您可以删除struct约束,然后t仍然是int并且string将是一个可为空的string So the question mark has the meaning: in case of a reference type it's a nullable reference type, otherwise it's just what it is.所以问号的意思是:在引用类型的情况下,它是一个可以为空的引用类型,否则它就是它。

You can't have both, a generic type that can be a nullable reference type or a nullable value type without using the desired generic type, so use int?你不能同时拥有一个泛型类型,它可以是一个可以为空的引用类型或一个可以为空的值类型而不使用所需的泛型类型,所以使用int? if it must be nullable.如果它必须可以为空。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM