C# 定义 class 实例永远不能为空(它只包含不包含数据)

C# define that a class instance can never be null (it only contains no data)

出于好奇:有没有办法创建一个 class,其对 class 实例的引用永远不会设置为 null? 就像只有一个只读指针,只能由 class 本身设置为 null。

我的想法是: 我希望有一个易于阅读/使用的对象,它要么与数据一起存在,要么不与数据一起存在(由 hasData = false 之类的属性显示)。它始终是可访问的,永远不应该为 null / 指向任何地方,作为副作用,它也消除了对象的 NullReferenceExceptions,这些对象有时应该没有值而不需要检查 null。

在这种情况下,您可能希望使用结构而不是 class。 Class 是引用类型,因此它的默认值为空,因此包含实例的变量可以为空(分配为空)。没有办法阻止它。另一方面,struct 是一个值类型,struct 的默认值是一个空结构 - 即一个结构,其成员设置为默认值(0 表示 int 字段,null 表示引用类型的字段等)

结构示例

public struct Foo
{
    public int Bar;
}

及其用法(注意它没有实例化但仍然不是空的)

Foo foo;
foo.Bar = 1;

可以在 MSDN sites 上找到有关结构的更多信息。

此功能(目前)不存在。 Roslyn 论坛上有很多关于不可空引用类型的讨论:non-nullable reference types (the one billion $ mistake)。但是目前你不能限制引用类型变量分配null值。

您可以改用值类型(结构),但它不存储在堆中,按值传递等

所有其他选项不能保证有人不会将 null 分配给您的引用类型的变量。但是您仍然可以使用 Null Object 模式之类的东西来简化您的生活(以与普通对象相同的方式处理没有数据的对象)。

正如 Anton 所提到的,您可以使用不能具有默认值 null 的结构。但我想你想要更像这样的东西:

public class DataObject
{
    public static bool HasData
    {
        get
        {
            return myObject != null;
        }
    }

    public static DataObject PresistentDataObject
    {
        get
        {
            return myObject;
        }
    }

    static DataObject myObject = new DataObject();
}

这段代码似乎是不好的做法。也许你想求助于单例依赖注入之类的东西,这样可以避免像这样设置状态class。

如果您的 class 被命名为 foo,那么您将至少有一个构造函数(可能更多)。在该构造函数中,您会将变量分配给 false。

public foo(){
    hasData = false;
}

正如@Anton 指出的那样,这仅在实例化变量时有效。 foo f = new foo();

如果您将其指定为 null,它仍将是 null: foo f = null;

I'm not sure, I understand the question correctly or not. Let me add some points here:

希望你误解了术语Instance,如果你创建了class的实例那么它就不会是null,让myClass成为class 你已经创建了。您没有使用 myClass myClassObject 创建 class 的任何实例。只有当class的实例分配给它时,myClassObject才会成为class的实例,直到那时它是null,这意味着不存在。

通常,此类问题背后的动机会驱动 qualities/properties 解决方案。

我想,这里的动机是避免(错误的)代码的运行时异常,这些代码试图访问空引用,就好像它持有一个实例一样。

class Foo<T> {
    T data; // might be null or hold an instance...
    Foo<T>() {
        data = GetInstanceOfTInMysteriousWays(); // might return null...
    }
    bool DoSomething() {
       return data.Value > 5; // might throw an exception...
    }
    // ... more members...
}

要防止此类错误,您可以借鉴 C# 的近亲语言 F#。 如果函数 T GetInstanceOfTInMysteriousWays<T>() 通过设计和约定被允许 return 一个实例或一个空值,那么该函数的更好设计是让它 return 而不是 T 而 Option<T>。那么,Foo.data的类型就不是T而是Option<T>DoSomething()中的用户代码不能简单地访问成员data.Value。因此,这种常见的错误模式将被消除。

// Improved code from above
class Foo<T> {
    Option<T> data; // Option is a struct type and cannot be null...
    Foo<T>() {
        data = GetInstanceOfTInMysteriousWays();
    }
    bool DoSomething() {
         if (data.IsSome() ) {
             return data.TryGetValue().Value > 5; 
         }
         return false;
    }
}

现在唯一的问题是,在 C# 中哪里可以找到该选项类型?有几个 github 项目创建了这样的类型(google 是你的朋友)。您还可以考虑 link F# 核心库并使用那里定义的 Option 类型,也许还有一个小助手,如 this gist snippet.

中所示

正如其他人所提到的,您需要一个 struct

不过,我们可以换个角度(class)来解决这个问题:

既然变量可以指向null,那么让我们定义一个不能为null的变量:

private Class1 _c = new Class1();
public Class1 c { get { return _c; } set { if (value != null) _c = value; } }

因此 c 不会设置为 null


A struct 根据您的要求:

struct Struct1
{
    public bool hasData { get { return Data != null; } }
    public Class1 Data;
}