简体   繁体   English

从索引器属性返回引用

[英]Returning a reference from an indexer property

I am creating a matrix struct and am trying to add an indexer to the matrix like so:我正在创建一个矩阵结构,并试图将索引器添加到矩阵中,如下所示:

public struct Vector4f
{
    public float X;
    public float Y;
    public float Z;
    public float W;
}

public struct Matrix4x4f
{
    public Vector4f X;
    public Vector4f Y;
    public Vector4f Z;
    public Vector4f W;

    public ref Vector4f this[int index]
    {
        get
        {
            return ref Unsafe.Add(ref X, index);
        }
    }
}

I am unable to get rid of the error in the getter however.但是,我无法摆脱 getter 中的错误。

CS8347: Cannot use a result of 'Unsafe.Add(ref Vector4f, int)' in this context because it may expose variables referenced by parameter 'source' outside of their declaration scope. CS8347:无法在此上下文中使用“Unsafe.Add(ref Vector4f, int)”的结果,因为它可能会在其声明 scope 之外公开参数“source”引用的变量。

I there a way to do what I am trying to do?我有办法做我想做的事吗? The goal is to be able to write the following (while still using value types):目标是能够编写以下内容(同时仍然使用值类型):

var m = new Matrix4x4f();
m[2].X = 3.14f;

This is probably related to CS8170 which is put in place to prevent references to fields of local / temporary instances to escape the scope in which they're valid.这可能与 CS8170 有关,该 CS8170 用于防止引用本地/临时实例的字段以逃避它们有效的范围。 S. Why can't a C# struct method return a reference to a field, but a non-member method can? S. 为什么 C# struct 方法不能返回对字段的引用,但非成员方法可以?

As provided by an answer there, you can still go "full unsafe" by using this, but then it's your responsibility to not wreak havoc with references to instances that went out of scope.正如那里的答案所提供的,您仍然可以通过使用它来“完全不安全”,但是您有责任不对超出范围的实例的引用造成严重破坏。

public unsafe ref Vector4f this[int index]
{
    get
    {
        fixed (Vector4f* pX = &X)
            return ref *(pX + index);
    }
}

You can add another indexer property with two parameters for access to vector components:您可以添加另一个带有两个参数的索引器属性以访问矢量组件:

public double this[int index1, int index2]
{
    get
    {
            switch (index1)
            {
                case 0: return X[index2];
                case 1: return Y[index2];
                case 2: return Z[index2];
                case 3: return W[index2];
            }
            throw new ArgumentOutOfRangeException(nameof(index1));
    }
    set
    {
            switch (index1)
            {
                case 0: X[index2] = value; break;
                case 1: Y[index2] = value; break;
                case 2: Z[index2] = value; break;
                case 3: W[index2] = value; break;
            }
            throw new ArgumentOutOfRangeException(nameof(index1));
        }
    }
}

You can achieve what you need by annotating the indexer (or its getter) with [System.Diagnostics.CodeAnalysis.UnscopedRef] :您可以通过使用[System.Diagnostics.CodeAnalysis.UnscopedRef]注释索引器(或其获取器)来实现所需的功能:

[System.Diagnostics.CodeAnalysis.UnscopedRef]
public ref Vector4f this[int index]
{
    get
    {
        return ref Unsafe.Add(ref X, index);
    }
}

This way, you don't need to use the unsafe context.这样,您就不需要使用unsafe的上下文。

While normally instance methods of structs are not allowed to return a reference to this (or any member of this ), the annotation overrides this behavior and makes returning a reference to this possible.虽然通常不允许结构的实例方法返回对this (或this的任何成员)的引用,但注释会覆盖此行为并使返回对this的引用成为可能。

This part of the documentation on low level struct improvements in C# 11 contains more information on [UnscopedRef] . C# 11 中有关低级结构改进的文档的这一部分包含有关[UnscopedRef]的更多信息。

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

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