繁体   English   中英

C#中可为空的字符串

[英]nullable string in C#

我知道只需使用null,C#中的字符串就可以为“ nullable”。

但是,可空类型的全部要点是我从编译器获得帮助[编辑:aka,类型错误:无法将苹果添加到香蕉中]

而使用这种“类型系统”的“空性取决于底层类型”会破坏我可能拥有的任何保证(这并非易事,因为这似乎首先就是使用类型系统的全部要点。 )

如果愿意,用C#处理此问题的标准方法是什么? 我是否要开设自己的“可空”课程?

编辑

我再改一下这个问题:

在C#中,确保被注释为可为空的变量不会分配给未注释为可为空的变量的标准方法是什么?

那就是: 所有类型的标准方式是什么,究竟是什么 关键字为您提供值类型。

如果您要询问确保某个方法的返回类型不为null方法,则有一个解决方案:该方法必须返回值类型。 每个返回引用类型的方法都可能返回null 您无能为力。

因此,您可以创建一个这样的struct以能够返回值类型:

public struct SurelyNotNull<T>
{
    private readonly T _value;

    public SurelyNotNull(T value)
    {
        if(value == null)
            throw new ArgumentNullException("value");
        _value = value;
    }

    public T Value
    {
        get { return _value; }
    }
}

现在应该返回字符串的方法可以返回SurelyNotNull<string>

这种方法的问题是:
没用 虽然保证方法的返回值不为null ,但SurelyNotNull<T>.Value的返回值不为。 乍一看,似乎可以保证它不为null。 但是可以这样,因为:
每个结构都有一个隐式的,公共的,无参数的构造函数, 即使定义了另一个构造函数也是如此
以下代码有效,并使用上面的struct编译:

new SurelyNotNull<string>();

结论:
在C#中,您无法实现您想做的事情。
您仍然可以使用这种方法,您只需要了解有人可以使用此类型并且仍然产生空值。 要在这种情况下快速失败,最好将检查添加到Value的getter并在_value为null时引发异常。

正如丹尼尔·希尔加斯(Daniel Hilgarth)所指出的,没有实现这一目标的防弹方法。 我的提议与他的提议相似,但又增加了一些安全性。 您可以自己决定收益是否超过在整个程序中使用包装器类型的成本。

struct NonNull<T> where T : class {
    private readonly T _value;
    private readonly bool _isSafe;

    public NonNull(T value) {
        if (value == null)
            throw new ArgumentNullException();
        _value = value;
        _isSafe = true;
    }
    public T Value {
        get {
            if (_isSafe) return _value;
            throw new ArgumentNullException();
        }
    }
    public static implicit operator T(NonNull<T> nonNull) {
        return nonNull.Value;
    }
}

static class NonNull {
    public static NonNull<T> Create<T>(T value) where T : class {
        return new NonNull<T>(value);
    }
}

包装器类型主要是为了使您的意图能够自我记录,因此不太可能使用零初始化的结构来绕过它,但是它会保留一个标志以指示它是否已正确初始化。 在那种公认的异常情况下,访问该值时将抛出ArgumentNullException

class Program {
    static void Main(string[] args) {
        IsEmptyString(NonNull.Create("abc")); //false
        IsEmptyString(NonNull.Create("")); //true
        IsEmptyString(null); //won't compile
        IsEmptyString(NonNull.Create<string>(null)); //ArgumentNullException 
        IsEmptyString(new NonNull<string>()); //bypassing, still ArgumentNullException
    }

    static bool IsEmptyString(NonNull<string> s) {
        return StringComparer.Ordinal.Equals(s, "");
    }
}

现在,这比偶尔的NRE好吗? 也许。 它可以节省大量样板参数检查。 您需要确定是否适合您的情况。 缺少像F#这样的编译器支持,无法提供编译时的空安全性,但是(可以说)您可以减轻运行时的安全性。

您可能希望在Microsoft的客户反馈网站上投票解决此问题: 在C#中添加不可为空的引用类型

您需要类似NotNull属性的东西。 使用这些将为您提供编译时警告和错误,并且在某些情况下,IDE会反馈有关将NULL值分配给NotNull属性的信息。

看到这个问题: C#:如何实现和使用NotNull和CanBeNull属性

所有引用类型都可以为空。 字符串是引用类型。

暂无
暂无

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

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