C#:如何将可选引用返回到结构

问题描述 投票:0回答:2

在 C# 中,如何编写一个可能返回或不返回结构体引用的函数?

我基本上想要的是一个返回类型

Nullable<ref OutboxSlot>
但编译器抱怨
ref
是一个意外的标记。

我想做的是这样的:

Nullable<ref SomeFieldStruct> GetCorrectField(ref SomeStruct s) {
  // Depending on some property of s either return null or a ref to a field of s
}

在 Rust 之类的东西中,我可以轻松声明像

Option<&mut SomeFieldStruct>
这样的返回类型。

PS:不,我不能使用课程。

c# return-type ref
2个回答
1
投票

在项目属性中,在编译中,必须选中“允许不安全代码”:

不要忘记在调试和发布中设置。

我将使用这个结构:

public struct SomeStruct
{
    public int Value;
    public SomeFieldStruct Field;
}

public struct SomeFieldStruct
{
    public double Value;
}

然后,创建你的方法:

public unsafe static SomeFieldStruct* GetCorrectField(ref SomeStruct s)
{
    // Depending on some property of s either return null or a ref to a field of s
    if (s.Value == 0)
    {
        fixed (SomeFieldStruct* field = &s.Field)
        {
            return field;
        }
    }

    return null;
}

如果 Value 为零,则返回结构的 Field 属性的地址。检查一下:

public unsafe static void Test()
{
    SomeStruct obj;
    obj.Value = 0;
    obj.Field.Value = 1.2;

    SomeFieldStruct* field = GetCorrectField(ref obj);
    if (field != null)
    {
        field->Value *= 10.0;
    }
}

对于指针,必须使用箭头 -> 而不是点。所有不安全的方法都必须包含 unsafe 关键字。


0
投票

您可以在此处使用

Span
。它有一个 constructor ,它只接受一个引用并包装它。您可以安全地编写这样的代码。

private T[] Array;
public Span<T> Get(int index) {
    if (index < 0 || index >= Array.Length) {
        return Span<T>.Empty;
    }
    return new Span<T>(ref Array[index]);
}

var item = Get(10);
if (!item.IsEmpty) {
   DoSomething(ref item[0])
}

展开单个参数跨度的语义并不伟大,但您现在也可以声明自己的

ref struct
类型来在 C#11 中包装您的引用。这也不再需要不安全的代码。

public readonly ref struct RefNullable<T> where T : struct {
    private readonly ref T _Value;
    public readonly bool HasValue => !Unsafe.IsNullRef(ref _Value);
    public ref T Value {
        get {
            if (HasValue) { throw new InvalidOperationException(); }
            return ref _Value;
        }
    }

    public RefNullable() { }
    public RefNullable(ref T val) => _Value = ref val;
}

不确定标准库中是否存在类似

RefNullable
的内容。我从搜索中找不到它。
ByReference
似乎是一件事,但我认为这不再受到鼓励。

如果在检查

Value
之前调用
HasValue
,我试图让编译器生成警告/错误,就像
Nullable<T>
现在启用了可空性检查一样,但无法弄清楚这一点。我认为
Nullable<T>
在可空性检查器中是特殊的。不幸的是,
[MaybeNull]
似乎被忽略了(大概是因为分析器知道结构类型不能为空,并且任何不可为空的结构都不会被视为可为空)。如果有人解决了这个问题,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.