Dela via


16 structs

16.1 Allmänt

Structs liknar klasser eftersom de representerar datastrukturer som kan innehålla datamedlemmar och funktionsmedlemmar. Men till skillnad från klasser är structs värdetyper och kräver inte heap-allokering. En variabel av en struct typ innehåller direkt data för struct, medan en variabel av en klasstyp innehåller en referens till data, den senare kallas för ett objekt.

Obs! Structs är särskilt användbara för små datastrukturer som har värdesemantik. Komplexa tal, punkter i ett koordinatsystem eller nyckel/värde-par i en ordlista är alla bra exempel på structs. Nyckeln till dessa datastrukturer är att de har få datamedlemmar, att de inte kräver användning av arvs- eller referenssemantik, snarare kan de implementeras bekvämt med hjälp av värdesemantik där tilldelningen kopierar värdet i stället för referensen. slutkommentar

Enligt beskrivningen i §8.3.5 är de enkla typer som tillhandahålls av C#, som int, doubleoch bool, i själva verket alla structtyper.

16.2 Struct-deklarationer

16.2.1 Allmänt

En struct_declaration är en type_declaration (§14.7) som deklarerar en ny struct:

struct_declaration
    : attributes? struct_modifier* 'ref'? 'partial'? 'struct'
      identifier type_parameter_list? struct_interfaces?
      type_parameter_constraints_clause* struct_body ';'?
    ;

En struct_declaration består av en valfri uppsättning attribut (§22), följt av en valfri uppsättning struct_modifier(§16.2.2), följt av en valfri ref modifierare (§16.2.3), följt av en valfri partiell modifierare (§15.2.7), följt av nyckelordet struct och en identifierare som namnger struct, följt av en valfri type_parameter_list specifikation (§15.2.3), följt av en valfri struct_interfaces specifikation (§16.2.5), följt av en valfri type_parameter_constraints-klausulsspecifikation (§15.2.5), följt av en struct_body (§16.2.6), eventuellt följt av semikolon.

En structdeklaration får inte tillhandahålla en type_parameter_constraints_clauses såvida den inte även tillhandahåller en type_parameter_list.

En struct-deklaration som tillhandahåller en type_parameter_list är en allmän structdeklaration. Dessutom är varje struct kapslad inuti en generisk klassdeklaration eller en generisk structdeklaration i sig en generisk structdeklaration, eftersom typargument för den innehållande typen ska levereras för att skapa en konstruerad typ (§8.4).

En struct-deklaration som innehåller ett ref nyckelord får inte ha en struct_interfaces del.

16.2.2 Struct-modifierare

En struct_declaration kan eventuellt innehålla en sekvens med struct_modifiers:

struct_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'readonly'
    | unsafe_modifier   // unsafe code support
    ;

unsafe_modifier (§23.2) är endast tillgänglig i osäker kod (§23).

Det är ett kompileringsfel för samma modifierare som visas flera gånger i en struct-deklaration.

Med undantag för readonlyhar modifierarna för en structdeklaration samma betydelse som en klassdeklaration (§15.2.2).

Modifieraren readonly anger att struct_declaration deklarerar en typ vars instanser är oföränderliga.

En skrivskyddad struct har följande begränsningar:

  • Vart och ett av dess instansfält ska också deklareras readonly.
  • Ingen av dess instansegenskaper får ha en set_accessor_declaration (§15.7.3).
  • Den skall inte deklarera några fältliknande händelser (§15.8.2).

När en instans av en skrivskyddad struct skickas till en metod behandlas den this som ett indataargument/parameter, vilket inte tillåter skrivåtkomst till instansfält (förutom konstruktorer).

16.2.3 Refmodifierare

Modifieraren ref anger att struct_declaration deklarerar en typ vars instanser allokeras i körningsstacken. Dessa typer kallas referensstruktureringstyper. Modifieraren ref deklarerar att instanser kan innehålla ref-liknande fält och får inte kopieras ur sin säkra kontext (§16.4.12). Reglerna för att fastställa en referens structs säkra kontext beskrivs i §16.4.12.

Det är ett kompileringsfel om en referens struct-typ används i någon av följande kontexter:

  • Som elementtyp för en matris.
  • Som den deklarerade typen av ett fält i en klass eller en struct som inte har ref modifieraren.
  • Boxas till System.ValueType eller System.Object.
  • Som ett typargument.
  • Som typ av ett tupppelelement.
  • En asynkron metod.
  • En iterator.
  • Det finns ingen konvertering från en ref struct typ till typen object eller typen System.ValueType.
  • En ref struct typ får inte deklareras för att implementera något gränssnitt.
  • En instansmetod som deklareras i object eller i System.ValueType men som inte åsidosätts i en ref struct typ ska inte anropas med en mottagare av den ref struct typen.
  • En instansmetod av en ref struct typ ska inte samlas in av metodgruppskonvertering till en ombudstyp.
  • En referens struct får inte fångas upp av ett lambda-uttryck eller en lokal funktion.

Obs! A ref struct får inte deklarera async instansmetoder eller använda en eller yield break -yield returninstruktion i en instansmetod, eftersom den implicita this parametern inte kan användas i dessa kontexter. slutkommentar

Dessa begränsningar säkerställer att en variabel av ref struct typen inte refererar till stackminne som inte längre är giltigt eller till variabler som inte längre är giltiga.

16.2.4 Partiell modifierare

Modifieraren partial anger att den här struct_declaration är en partiell typdeklaration. Flera partiella structdeklarationer med samma namn inom ett omslutande namnområde eller typdeklaration kombineras för att bilda en structdeklaration, enligt de regler som anges i §15.2.7.

16.2.5 Struct-gränssnitt

En structdeklaration kan innehålla en struct_interfaces specifikation, i vilket fall structen sägs direkt implementera de angivna gränssnittstyperna. För en konstruerad structtyp, inklusive en kapslad typ som deklarerats inom en allmän typdeklaration (§15.3.9.7), erhålls varje implementerad gränssnittstyp genom att ersätta, för varje type_parameter i det angivna gränssnittet, motsvarande type_argument av den konstruerade typen.

struct_interfaces
    : ':' interface_type_list
    ;

Hanteringen av gränssnitt på flera delar av en partiell structdeklaration (§15.2.7) diskuteras ytterligare i §15.2.4.3.

Gränssnittsimplementeringar diskuteras ytterligare i §18.6.

16.2.6 Struct brödtext

Struct_body för en struct definierar medlemmarna i structen.

struct_body
    : '{' struct_member_declaration* '}'
    ;

16.3 Struct medlemmar

Medlemmarna i en struct består av de medlemmar som introduceras av dess struct_member_declarations och de medlemmar som ärvts från typen System.ValueType.

struct_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | static_constructor_declaration
    | type_declaration
    | fixed_size_buffer_declaration   // unsafe code support
    ;

fixed_size_buffer_declaration (§23.8.2) är endast tillgänglig i osäker kod (§23).

Obs! Alla typer av class_member_declarationutom finalizer_declaration är också struct_member_declarations. slutkommentar

Förutom de skillnader som anges i §16.4 gäller även beskrivningarna av klassmedlemmar som anges i §15.3 till och med §15.12 för structmedlemmar.

16.4 Skillnader i klass och struct

16.4.1 Allmänt

Structs skiljer sig från klasser på flera viktiga sätt:

  • Structs är värdetyper (§16.4.2).
  • Alla structtyper ärver implicit från klassen System.ValueType (§16.4.3).
  • Tilldelning till en variabel av en structtyp skapar en kopia av värdet som tilldelas (§16.4.4).
  • Standardvärdet för en struct är det värde som genereras genom att ange alla fält till standardvärdet (§16.4.5).
  • Boxnings- och avboxningsåtgärder används för att konvertera mellan en structtyp och vissa referenstyper (§16.4.6).
  • Det menande av this är olikt inom structmedlemmar (§16.4.7).
  • Instansfältdeklarationer för en struct tillåts inte inkludera variabelinitierare (§16.4.8).
  • En struct får inte deklarera en parameterlös instanskonstruktor (§16.4.9).
  • En struct får inte deklarera en finalizer.

16.4.2 Värdesemantik

Structs är värdetyper (§8.3) och sägs ha värdesemantik. Klasser är däremot referenstyper (§8.2) och sägs ha referenssemantik.

En variabel av en structtyp innehåller direkt data för structen, medan en variabel av en klasstyp innehåller en referens till ett objekt som innehåller data. När en struct B innehåller ett instansfält av typen A och A är en structtyp är det ett kompileringsfel för A att vara beroende B av eller en typ som har skapats från B. A struct Xberor direkt på en struct Y om X innehåller ett instansfält av typen Y. Med den här definitionen är den fullständiga uppsättningen structs som en struct är beroende av den transitiva stängningen av direkt beroende av relationen.

Exempel:

struct Node
{
    int data;
    Node next; // error, Node directly depends on itself
}

är ett fel eftersom Node det innehåller ett instansfält av sin egen typ. Ett annat exempel

struct A { B b; }
struct B { C c; }
struct C { A a; }

är ett fel eftersom var och en av typerna A, Boch C är beroende av varandra.

slutexempel

Med klasser är det möjligt för två variabler att referera till samma objekt och därmed möjligt för åtgärder på en variabel att påverka objektet som refereras av den andra variabeln. Med structs har variablerna var och en sin egen kopia av data (förutom när det gäller bireferensparametrar), och det är inte möjligt för åtgärder på den ena att påverka den andra. Förutom när det uttryckligen är nullbart (§8.3.12) är det inte möjligt för värden av en structtyp att vara null.

Obs! Om en struct innehåller ett fält av referenstyp kan innehållet i det refererade objektet ändras av andra åtgärder. Men värdet för själva fältet, dvs. vilket objekt det refererar till, kan inte ändras genom en mutation av ett annat structvärde. slutkommentar

Exempel: Med tanke på följande

struct Point
{
    public int x, y;

    public Point(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    static void Main()
    {
        Point a = new Point(10, 10);
        Point b = a;
        a.x = 100;
        Console.WriteLine(b.x);
    }
}

utdata är 10. Tilldelningen av a till b skapar en kopia av värdet och b påverkas därför inte av tilldelningen till a.x. Om utdata i stället hade Point deklarerats som en klass skulle det bero 100 på att a och b refererar till samma objekt.

slutexempel

16.4.3 Arv

Alla structtyper ärver implicit från klassen System.ValueType, som i sin tur ärver från klassen object. En struct-deklaration kan ange en lista över implementerade gränssnitt, men det är inte möjligt för en struct-deklaration att ange en basklass.

Struct-typer är aldrig abstrakta och är alltid implicit förseglade. Modifierarna abstract och sealed tillåts därför inte i en struct-deklaration.

Eftersom arv inte stöds för structs kan den deklarerade tillgängligheten för en struct-medlem inte vara protected, private protectedeller protected internal.

Funktionsmedlemmar i en struct kan inte vara abstrakta eller virtuella, och override modifieraren får endast åsidosätta metoder som ärvts från System.ValueType.

16.4.4 Tilldelning

Tilldelning till en variabel av en structtyp skapar en kopia av värdet som tilldelas. Detta skiljer sig från tilldelning till en variabel av en klasstyp, som kopierar referensen men inte det objekt som identifieras av referensen.

Precis som en tilldelning skapas en kopia av structen när en struct skickas som en värdeparameter eller returneras som ett resultat av en funktionsmedlem. En struct kan skickas med referens till en funktionsmedlem med hjälp av en bireferensparameter.

När en egenskap eller indexerare för en struct är målet för en tilldelning ska instansuttrycket som är associerat med egenskapen eller indexerarens åtkomst klassificeras som en variabel. Om instansuttrycket klassificeras som ett värde uppstår ett kompileringsfel. Detta beskrivs närmare i §12.21.2.

16.4.5 Standardvärden

Enligt beskrivningen i §9.3 initieras flera typer av variabler automatiskt till standardvärdet när de skapas. För variabler av klasstyper och andra referenstyper är nulldet här standardvärdet . Eftersom structs är värdetyper som inte kan vara null, är standardvärdet för en struct det värde som genereras genom att ange alla värdetypsfält till standardvärdet och alla referenstypfält till null.

Exempel: Med hänvisning till structen Point som deklarerats ovan, exemplet

Point[] a = new Point[100];

initierar var Point och en i matrisen till det värde som skapas genom att fälten x och y anges till noll.

slutexempel

Standardvärdet för en struct motsvarar det värde som returneras av standardkonstruktorn för structen (§8.3.3). Till skillnad från en klass tillåts inte en struct deklarera en parameterlös instanskonstruktor. I stället har varje struct implicit en parameterlös instanskonstruktor, som alltid returnerar det värde som är resultatet av att ange alla fält till deras standardvärden.

Obs! Structs bör utformas för att betrakta standardinitieringstillståndet som ett giltigt tillstånd. I exemplet

struct KeyValuePair
{
    string key;
    string value;

    public KeyValuePair(string key, string value)
    {
        if (key == null || value == null)
        {
            throw new ArgumentException();
        }

        this.key = key;
        this.value = value;
    }
}

den användardefinierade instanskonstruktorn skyddar endast mot null värden där den uttryckligen anropas. I de fall där en KeyValuePair variabel är föremål för standardvärdeinitiering blir nullfälten key och value , och structen bör förberedas för att hantera det här tillståndet.

slutkommentar

16.4.6 Boxning och avboxning

Ett värde av en klasstyp kan konverteras till typ object eller till en gränssnittstyp som implementeras av klassen genom att bara behandla referensen som en annan typ vid kompileringstid. På samma sätt kan ett värde av typen object eller ett värde av en gränssnittstyp konverteras tillbaka till en klasstyp utan att referensen ändras (men naturligtvis krävs en körningstypskontroll i det här fallet).

Eftersom structs inte är referenstyper implementeras dessa åtgärder på olika sätt för structtyper. När ett värde av en structtyp konverteras till vissa referenstyper (enligt definitionen i §10.2.9), sker en boxningsåtgärd. På samma sätt, när ett värde av vissa referenstyper (enligt definitionen i §10.3.7) konverteras tillbaka till en structtyp, sker en avboxningsåtgärd. En viktig skillnad jämfört med samma åtgärder för klasstyper är att boxning och avboxning kopierar structvärdet antingen till eller från den boxade instansen.

Obs! Efter en boxnings- eller avboxningsåtgärd återspeglas inte ändringar som görs i den oboxade struct i rutan struct. slutkommentar

Mer information om boxning och unboxing finns i §10.2.9 och §10.3.7.

16.4.7 Innebörden av detta

Innebörden av this i en struct skiljer sig från innebörden av this i en klass, enligt beskrivningen i §12.8.14. När en struct-typ åsidosätter en virtuell metod som ärvts från System.ValueType (till exempel Equals, GetHashCodeeller ToString), orsakar anrop av den virtuella metoden via en instans av struct-typen inte boxning. Detta gäller även när struct används som en typparameter och anropet sker via en instans av typparametertypen.

Exempel:

struct Counter
{
    int value;
    public override string ToString() 
    {
        value++;
        return value.ToString();
    }
}

class Program
{
    static void Test<T>() where T : new()
    {
        T x = new T();
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
    }

    static void Main() => Test<Counter>();
}

Programmets utdata är:

1
2
3

Även om det är dålig stil för ToString att ha biverkningar, visar exemplet att ingen boxning inträffade för de tre anropen av x.ToString().

slutexempel

På samma sätt sker boxning aldrig implicit vid åtkomst till en medlem på en begränsad typparameter när medlemmen implementeras inom värdetypen. Anta till exempel att ett gränssnitt ICounter innehåller en metod Increment, som kan användas för att ändra ett värde. Om ICounter används som en begränsning anropas implementeringen av Increment metoden med en referens till variabeln som Increment anropades, aldrig en rutad kopia.

Exempel:

interface ICounter
{
    void Increment();
}

struct Counter : ICounter
{
    int value;

    public override string ToString() => value.ToString();

    void ICounter.Increment() => value++;
}

class Program
{
    static void Test<T>() where T : ICounter, new()
    {
        T x = new T();
        Console.WriteLine(x);
        x.Increment();              // Modify x
        Console.WriteLine(x);
        ((ICounter)x).Increment();  // Modify boxed copy of x
        Console.WriteLine(x);
    }

    static void Main() => Test<Counter>();
}

Det första anropet för att Increment ändra värdet i variabeln x. Detta motsvarar inte det andra anropet till Increment, som ändrar värdet i en rutad kopia av x. Därför är programmets utdata:

0
1
1

slutexempel

16.4.8 Fältinitierare

Enligt beskrivningen i §16.4.5 består standardvärdet för en struct av det värde som är resultatet av att ange alla värdetypsfält till deras standardvärde och alla referenstypfält till null. Därför tillåter en struct inte instansfältdeklarationer att inkludera variabelinitierare. Den här begränsningen gäller endast för instansfält. Statiska fält i en struct tillåts inkludera variabelinitierare.

Exempel: Följande

struct Point
{
    public int x = 1; // Error, initializer not permitted
    public int y = 1; // Error, initializer not permitted
}

är ett fel eftersom instansfältdeklarationerna innehåller variabelinitierare.

slutexempel

16.4.9 Konstruktorer

Till skillnad från en klass tillåts inte en struct deklarera en parameterlös instanskonstruktor. I stället har varje struct implicit en parameterlös instanskonstruktor, som alltid returnerar det värde som är resultatet av att ange alla värdetypsfält till standardvärdet och alla referenstypfält till null (§8.3.3). En struct kan deklarera att instanskonstruktorer har parametrar.

Exempel: Med tanke på följande

struct Point
{
    int x, y;

    public Point(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    static void Main()
    {
        Point p1 = new Point();
        Point p2 = new Point(0, 0);
    }
}

-uttrycken skapar både en Point med x och y initieras till noll.

slutexempel

En struct-instanskonstruktor får inte innehålla en konstruktorinitierare av formuläret base(argument_list), där argument_list är valfritt.

Parametern this för en struct-instanskonstruktor motsvarar en utdataparameter av typen struct. this Därför skall definitivt tilldelas (§9.4) på varje plats där konstruktorn returnerar. På samma sätt kan den inte läsas (även implicit) i konstruktorns brödtext innan den definitivt tilldelas.

Om struct-instanskonstruktorn anger en konstruktorinitierare anses initieraren vara en bestämd tilldelning till detta som inträffar före konstruktorns brödtext. Därför har själva brödtexten inga initieringskrav.

Exempel: Överväg implementeringen av instanskonstruktorn nedan:

struct Point
{
    int x, y;

    public int X
    {
        set { x = value; }
    }

    public int Y 
    {
        set { y = value; }
    }

    public Point(int x, int y) 
    {
        X = x; // error, this is not yet definitely assigned
        Y = y; // error, this is not yet definitely assigned
    }
}

Ingen instansfunktionsmedlem (inklusive uppsättningsåtkomsterna för egenskaperna X och Y) kan anropas förrän alla fält i den struct som skapas definitivt har tilldelats. Observera dock att om Point det var en klass i stället för en struct skulle instanskonstruktorimplementeringen tillåtas. Det finns ett undantag till detta och det omfattar automatiskt implementerade egenskaper (§15.7.4). De bestämda tilldelningsreglerna (§12.21.2) undantar specifikt tilldelning till en autoegenskap av en structtyp inom en instanskonstruktor av den typen: en sådan tilldelning anses vara en bestämd tilldelning av det dolda bakgrundsfältet för den automatiska egenskapen. Därför tillåts följande:

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    {
        X = x; // allowed, definitely assigns backing field
        Y = y; // allowed, definitely assigns backing field
   }
}

slutexempel]

16.4.10 Statiska konstruktorer

Statiska konstruktorer för structs följer de flesta av samma regler som för klasser. Körningen av en statisk konstruktor för en struct-typ utlöses av den första av följande händelser som inträffar inom en programdomän:

  • En statisk medlem av structtypen refereras till.
  • En explicit deklarerad konstruktor av typen struct anropas.

Obs! Skapandet av standardvärden (§16.4.5) av structtyper utlöser inte den statiska konstruktorn. (Ett exempel på detta är det initiala värdet för element i en matris.) slutkommentar

16.4.11 Automatiskt implementerade egenskaper

Automatiskt implementerade egenskaper (§15.7.4) använder dolda bakgrundsfält, som endast är tillgängliga för egenskapsåtkomsterna.

Obs! Den här åtkomstbegränsningen innebär att konstruktorer i structs som innehåller automatiskt implementerade egenskaper ofta behöver en explicit konstruktorinitierare där de annars inte skulle behöva en, för att uppfylla kravet på alla fält som definitivt tilldelas innan någon funktionsmedlem anropas eller konstruktorn returnerar. slutkommentar

16.4.12 Villkor för säker kontext

16.4.12.1 Allmänt

Vid kompilering är varje uttryck associerat med en kontext där den instansen och alla dess fält kan nås på ett säkert sätt, dess säkra kontext. Safe-context är en kontext som omsluter ett uttryck, vilket är säkert för värdet att fly till.

Alla uttryck vars kompileringstidstyp inte är en referens-struct har en säker kontext av anroparkontext.

Ett default uttryck för alla typer har safe-context för anroparkontext.

För alla icke-standarduttryck vars kompileringstidstyp är en referensstruct har en safe-context definierad av följande avsnitt.

Safe-context registrerar vilken kontext ett värde kan kopieras till. Med en tilldelning från ett uttryck E1 med en safe-context S1, till ett uttryck E2 med safe-context S2, är det ett fel om S2 är en bredare kontext än S1.

Det finns tre olika safe-context-värden, samma som referens-safe-context-värdena som definierats för referensvariabler (§9.7.2): declaration-block, function-member och caller-context. Ett uttrycks säkra kontext begränsar dess användning enligt följande:

  • För ett returmeddelande return e1ska säkerhetskontexten e1 för vara anroparkontext.
  • För en tilldelning e1 = e2 ska säkerhetskontexten e2 vara minst lika bred som säkerhetskontexten e1för .

För ett metodanrop om det finns ett ref eller out ett argument av en ref struct typ (inklusive mottagaren om inte typen är readonly), med safe-context S1, kan inget argument (inklusive mottagaren) ha en smalare säker kontext än S1.

16.4.12.2 Parametersäker kontext

En parameter av typen ref struct, inklusive parametern this för en instansmetod, har en säker kontext av anroparkontext.

16.4.12.3 Säker kontext för lokal variabel

En lokal variabel av typen ref struct har en säker kontext enligt följande:

  • Om variabeln är en iterationsvariabel för en foreach loop är variabelns safe-context samma som safe-context för loopens foreach uttryck.
  • Om variabelns deklaration annars har en initiering är variabelns safe-context samma som initiatorns säkra kontext.
  • I annat fall är variabeln ennitialiserad vid deklarationspunkten och har en säker kontext av anroparkontext.

16.4.12.4 Fältsäker kontext

En referens till ett fält e.F, där typen av F är en referens-struct-typ, har en säker kontext som är samma som safe-context för e.

16.4.12.5 Operatorer

Tillämpningen av en användardefinierad operatör behandlas som ett metodanrop (§16.4.12.6).

För en operator som ger ett värde, till exempel e1 + e2 eller c ? e1 : e2, är safe-context för resultatet den smalaste kontexten bland operatorns säkra kontexter. För en unary-operator som ger ett värde, till exempel +e, är resultatets säkra kontext därför operandens säkra kontext.

Obs! Den första operanden för en villkorsoperator är en bool, så dess safe-context är caller-context. Av detta följer att den resulterande säkra kontexten är den smalaste säkra kontexten för den andra och tredje operanden. slutkommentar

16.4.12.6 Metod- och egenskapsanrop

Ett värde som härrör från en metodanrop e1.M(e2, ...) eller egenskapsanrop e.P har en säker kontext för den minsta av följande kontexter:

  • anroparkontext.
  • Safe-context för alla argumentuttryck (inklusive mottagaren).

Ett egenskapsanrop (antingen get eller set) behandlas som en metodanrop av den underliggande metoden av ovanstående regler.

16.4.12.7 stackalloc

Resultatet av ett stackalloc-uttryck har safe-context för function-member.

16.4.12.8 Konstruktoranrop

Ett new uttryck som anropar en konstruktor följer samma regler som en metodanrop som anses returnera den typ som skapas.

Dessutom är safe-context den minsta av de säkra kontexterna för alla argument och operander för alla objektinitieringsuttryck, rekursivt, om någon initiator finns.

Obs! Dessa regler förlitar sig på Span<T> att inte ha någon konstruktor i följande formulär:

public Span<T>(ref T p)

En sådan konstruktor gör att instanser av Span<T> används som fält som kan skiljas från ett ref fält. Säkerhetsreglerna som beskrivs i det här dokumentet beror på att ref fält inte är en giltig konstruktion i C# eller .NET. slutkommentar