ref (odwołanie w C#)ref (C# Reference)

Słowo kluczowe ref wskazuje wartość, która jest przenoszona przez odwołanie.The ref keyword indicates a value that is passed by reference. Jest on używany w czterech różnych kontekstach:It is used in four different contexts:

  • W sygnaturze metody i w wywołaniu metody, aby przekazać argument do metody przez odwołanie.In a method signature and in a method call, to pass an argument to a method by reference. Aby uzyskać więcej informacji, zobacz przekazywanie argumentu przez odwołanie.For more information, see Passing an argument by reference.
  • W podpisie metody, aby zwrócić wartość do obiektu wywołującego przez odwołanie.In a method signature, to return a value to the caller by reference. Aby uzyskać więcej informacji, zobacz odwołania do zwracanych wartości.For more information, see Reference return values.
  • W treści elementu członkowskiego, aby wskazać, że wartość zwracana przez odwołanie jest przechowywana lokalnie jako odwołanie, które obiekt wywołujący zamierza zmodyfikować lub ogólnie rzecz biorąc, zmienna lokalna uzyskuje dostęp do innej wartości przez odwołanie.In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify or, in general, a local variable accesses another value by reference. Aby uzyskać więcej informacji, zobacz odwołania lokalne.For more information, see Ref locals.
  • W deklaracji struct, aby zadeklarować ref struct lub readonly ref struct.In a struct declaration to declare a ref struct or a readonly ref struct. Aby uzyskać więcej informacji, zobacz typy struktury ref.For more information, see ref struct types.

Przekazywanie argumentu przez odwołaniePassing an argument by reference

W przypadku użycia na liście parametrów metody ref słowo kluczowe wskazuje, że argument jest przenoszona przez odwołanie, a nie przez wartość.When used in a method's parameter list, the ref keyword indicates that an argument is passed by reference, not by value. Słowo kluczowe ref powoduje, że parametr formalny jest aliasem dla argumentu, który musi być zmienną.The ref keyword makes the formal parameter an alias for the argument, which must be a variable. Innymi słowy, każda operacja na parametrze jest wykonywana na argumencie.In other words, any operation on the parameter is made on the argument. Na przykład, jeśli obiekt wywołujący przekazuje wyrażenie zmiennej lokalnej lub wyrażenie dostępu do elementu tablicy, a wywoływana metoda zastępuje obiekt, do którego odwołuje się parametr ref, wówczas zmienna lokalna obiektu wywołującego lub element array odwołuje się teraz do nowego obiektu, gdy Zwraca metodę.For example, if the caller passes a local variable expression or an array element access expression, and the called method replaces the object to which the ref parameter refers, then the caller’s local variable or the array element now refers to the new object when the method returns.

Uwaga

Nie należy mylić koncepcji przekazywania przez odwołanie z koncepcją typów referencyjnych.Do not confuse the concept of passing by reference with the concept of reference types. Te dwa koncepcje nie są takie same.The two concepts are not the same. Parametr metody może być modyfikowany przez ref niezależnie od tego, czy jest to typ wartości czy typ referencyjny.A method parameter can be modified by ref regardless of whether it is a value type or a reference type. Nie istnieje opakowanie typu wartości, gdy jest ono przesyłane przez odwołanie.There is no boxing of a value type when it is passed by reference.

Aby użyć parametru ref, zarówno definicja metody, jak i Metoda wywołująca muszą jawnie użyć słowa kluczowego ref, jak pokazano w poniższym przykładzie.To use a ref parameter, both the method definition and the calling method must explicitly use the ref keyword, as shown in the following example.

void Method(ref int refArgument)
{
    refArgument = refArgument + 44;
}

int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45

Argument, który jest przesyłany do ref lub parametru in, musi zostać zainicjowany przed jego przekazaniem.An argument that is passed to a ref or in parameter must be initialized before it is passed. Różni się to od parametrów out , których argumenty nie muszą być jawnie inicjowane przed ich przekazaniem.This differs from out parameters, whose arguments do not have to be explicitly initialized before they are passed.

Elementy członkowskie klasy nie mogą mieć sygnatur, które różnią się tylko ref, inlub out.Members of a class can't have signatures that differ only by ref, in, or out. Błąd kompilatora występuje, jeśli jedyną różnicą między dwoma elementami członkowskimi tego typu jest, że jedna z nich ma parametr ref, a drugi ma outlub in parametr.A compiler error occurs if the only difference between two members of a type is that one of them has a ref parameter and the other has an out, or in parameter. Poniższy kod, na przykład, nie kompiluje.The following code, for example, doesn't compile.

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

Jednakże metody mogą być przeciążone, gdy jedna metoda ma parametr ref, inlub out, a drugi ma parametr value, jak pokazano w poniższym przykładzie.However, methods can be overloaded when one method has a ref, in, or out parameter and the other has a value parameter, as shown in the following example.

class RefOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
}

W innych sytuacjach, które wymagają dopasowania podpisu, takich jak ukrywanie lub zastępowanie, in, refi out są częścią podpisu i nie pasują do siebie nawzajem.In other situations that require signature matching, such as hiding or overriding, in, ref, and out are part of the signature and don't match each other.

Właściwości nie są zmiennymi.Properties are not variables. Są to metody i nie można ich przekazywać do parametrów ref.They are methods, and cannot be passed to ref parameters.

Nie można użyć słów kluczowych ref, ini out dla następujących rodzajów metod:You can't use the ref, in, and out keywords for the following kinds of methods:

  • Metody asynchroniczne zdefiniowane za pomocą modyfikatora Async .Async methods, which you define by using the async modifier.
  • Metody iteratorów, które zawierają instrukcję yield return lub yield break.Iterator methods, which include a yield return or yield break statement.

Przekazywanie argumentu przez odwołanie: przykładPassing an argument by reference: An example

Poprzednie przykłady przechodzą typy wartości według odwołania.The previous examples pass value types by reference. Możesz również użyć słowa kluczowego ref, aby przekazać typy odwołań przez odwołanie.You can also use the ref keyword to pass reference types by reference. Przekazywanie typu referencyjnego przez odwołanie włącza wywoływaną metodę, aby zastąpić obiekt, do którego odwołuje się parametr Reference w wywołującym.Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller. Lokalizacja przechowywania obiektu jest przenoszona do metody jako wartość parametru Reference.The storage location of the object is passed to the method as the value of the reference parameter. Jeśli zmienisz wartość w lokalizacji magazynu parametru (w celu wskazywania nowego obiektu), zmienisz również lokalizację magazynu, do którego odwołuje się obiekt wywołujący.If you change the value in the storage location of the parameter (to point to a new object), you also change the storage location to which the caller refers. Poniższy przykład przekazuje wystąpienie typu referencyjnego jako parametr ref.The following example passes an instance of a reference type as a ref parameter.

class Product
{
    public Product(string name, int newID)
    {
        ItemName = name;
        ItemID = newID;
    }

    public string ItemName { get; set; }
    public int ItemID { get; set; }
}

private static void ChangeByReference(ref Product itemRef)
{
    // Change the address that is stored in the itemRef parameter.   
    itemRef = new Product("Stapler", 99999);

    // You can change the value of one of the properties of
    // itemRef. The change happens to item in Main as well.
    itemRef.ItemID = 12345;
}

private static void ModifyProductsByReference()
{
    // Declare an instance of Product and display its initial values.
    Product item = new Product("Fasteners", 54321);
    System.Console.WriteLine("Original values in Main.  Name: {0}, ID: {1}\n",
        item.ItemName, item.ItemID);

    // Pass the product instance to ChangeByReference.
    ChangeByReference(ref item);
    System.Console.WriteLine("Back in Main.  Name: {0}, ID: {1}\n",
        item.ItemName, item.ItemID);
}

// This method displays the following output:
// Original values in Main.  Name: Fasteners, ID: 54321
// Back in Main.  Name: Stapler, ID: 12345        

Aby uzyskać więcej informacji na temat przekazywania typów odwołań według wartości i według odwołania, zobacz przekazywanie parametrów typu odwołania.For more information about how to pass reference types by value and by reference, see Passing Reference-Type Parameters.

Odwoływanie się do zwracanych wartościReference return values

Wartości zwracane przez odwołanie (lub zwroty odwołań) to wartości, które Metoda zwraca przez odwołanie do obiektu wywołującego.Reference return values (or ref returns) are values that a method returns by reference to the caller. Oznacza to, że obiekt wywołujący może zmodyfikować wartość zwróconą przez metodę, a ta zmiana jest odzwierciedlona w stanie obiektu, który zawiera metodę.That is, the caller can modify the value returned by a method, and that change is reflected in the state of the object that contains the method.

Wartość zwracana przez odwołanie jest definiowana przy użyciu słowa kluczowego ref:A reference return value is defined by using the ref keyword:

  • W podpisie metody.In the method signature. Na przykład następująca sygnatura metody wskazuje, że metoda GetCurrentPrice zwraca wartość Decimal przez odwołanie.For example, the following method signature indicates that the GetCurrentPrice method returns a Decimal value by reference.
public ref decimal GetCurrentPrice()
  • Między tokenem return i zmienną zwróconą w instrukcji return w metodzie.Between the return token and the variable returned in a return statement in the method. Na przykład:For example:
return ref DecimalArray[0];

Aby obiekt wywołujący zmodyfikował stan obiektu, wartość zwracana odwołania musi być przechowywana w zmiennej, która jest jawnie zdefiniowana jako lokalna jako ref.In order for the caller to modify the object's state, the reference return value must be stored to a variable that is explicitly defined as a ref local.

Wywołana metoda może również deklarować wartość zwracaną jako ref readonly, aby zwrócić wartość przez odwołanie, i wymusić, że wywoływany kod nie może zmodyfikować zwracanej wartości.The called method may also declare the return value as ref readonly to return the value by reference, and enforce that the calling code cannot modify the returned value. Metoda wywołująca może uniknąć kopiowania zwracanej wartości przez zapisanie wartości w lokalnej zmiennej ref ReadOnly .The calling method can avoid copying the returned valued by storing the value in a local ref readonly variable.

Aby zapoznać się z przykładem, zobacz przykład ref Returns i ref locales.For an example, see A ref returns and ref locals example.

Odwołania lokalneRef locals

Referencyjna zmienna lokalna służy do odwoływania się do wartości zwracanych przy użyciu return ref.A ref local variable is used to refer to values returned using return ref. Nie można zainicjować zmiennej lokalnej ref do wartości zwracanej niebędącej odwołaniem.A ref local variable cannot be initialized to a non-ref return value. Innymi słowy, prawa strona inicjowania musi być odwołaniem.In other words, the right hand side of the initialization must be a reference. Wszelkie modyfikacje wartości lokalnego elementu ref są odzwierciedlane w stanie obiektu, którego Metoda zwróciła wartość przez odwołanie.Any modifications to the value of the ref local are reflected in the state of the object whose method returned the value by reference.

Można zdefiniować odwołanie lokalne przy użyciu słowa kluczowego ref przed deklaracją zmiennej, a także bezpośrednio przed wywołaniem metody, która zwraca wartość przez odwołanie.You define a ref local by using the ref keyword before the variable declaration, as well as immediately before the call to the method that returns the value by reference.

Na przykład poniższa instrukcja definiuje wartość lokalną ref zwracaną przez metodę o nazwie GetEstimatedValue:For example, the following statement defines a ref local value that is returned by a method named GetEstimatedValue:

ref decimal estValue = ref Building.GetEstimatedValue();

Możesz uzyskać dostęp do wartości przez odwołanie w ten sam sposób.You can access a value by reference in the same way. W niektórych przypadkach uzyskanie dostępu do wartości przez odwołanie zwiększa wydajność poprzez uniknięcie potencjalnie kosztownej operacji kopiowania.In some cases, accessing a value by reference increases performance by avoiding a potentially expensive copy operation. Na przykład poniższa instrukcja pokazuje, jak jedna z nich może definiować wartość lokalna ref, która jest używana do odwoływania się do wartości.For example, the following statement shows how one can define a ref local value that is used to reference a value.

ref VeryLargeStruct reflocal = ref veryLargeStruct;

Należy zauważyć, że w obu przykładach słowo kluczowe ref musi być używane w obu miejscach lub kompilator generuje błąd CS8172 "nie można zainicjować zmiennej przez odwołanie za pomocą wartości".Note that in both examples the ref keyword must be used in both places, or the compiler generates error CS8172, "Cannot initialize a by-reference variable with a value."

Począwszy od C# 7,3, Zmienna iteracji instrukcji foreach może być lokalną zmienną lokalną typu ref lub ref tylko do odczytu.Beginning with C# 7.3, the iteration variable of the foreach statement can be ref local or ref readonly local variable. Aby uzyskać więcej informacji, zobacz artykuł instrukcji foreach .For more information, see the foreach statement article.

Odwołania do elementów lokalnych ReadOnlyRef readonly locals

Wartość Ref Local ReadOnly jest używana do odwoływania się do wartości zwracanych przez metodę lub właściwość, która ma ref readonly w jej sygnaturze i używa return ref.A ref readonly local is used to refer to values returned by the method or property that has ref readonly in its signature and uses return ref. Zmienna ref readonly łączy właściwości zmiennej lokalnej ref z zmienną readonly: jest to alias do magazynu, do którego jest przypisany, i nie można go modyfikować.A ref readonly variable combines the properties of a ref local variable with a readonly variable: it is an alias to the storage it's assigned to, and it cannot be modified.

Przykład odwołania ref i lokalne odwołania refA ref returns and ref locals example

W poniższym przykładzie zdefiniowano klasę Book, która ma dwa String pola, Title i Author.The following example defines a Book class that has two String fields, Title and Author. Definiuje również klasę BookCollection, która zawiera prywatną tablicę obiektów Book.It also defines a BookCollection class that includes a private array of Book objects. Poszczególne obiekty książek są zwracane przez odwołanie poprzez wywołanie jego metody GetBookByTitle.Individual book objects are returned by reference by calling its GetBookByTitle method.


public class Book
{
    public string Author;
    public string Title;
}

public class BookCollection
{
    private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
                        new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
                       };
    private Book nobook = null;

    public ref Book GetBookByTitle(string title)
    {
        for (int ctr = 0; ctr < books.Length; ctr++)
        {
            if (title == books[ctr].Title)
                return ref books[ctr];
        }
        return ref nobook;
    }

    public void ListBooks()
    {
        foreach (var book in books)
        {
            Console.WriteLine($"{book.Title}, by {book.Author}");
        }
        Console.WriteLine();
    }
}

Gdy obiekt wywołujący przechowuje wartość zwróconą przez metodę GetBookByTitle jako odwołanie lokalne, zmiany, które obiekt wywołujący wprowadza do wartości zwracanej, są odzwierciedlane w obiekcie BookCollection, jak pokazano w poniższym przykładzie.When the caller stores the value returned by the GetBookByTitle method as a ref local, changes that the caller makes to the return value are reflected in the BookCollection object, as the following example shows.

var bc = new BookCollection();
bc.ListBooks();

ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
    book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
//       Call of the Wild, The, by Jack London
//       Tale of Two Cities, A, by Charles Dickens
//       
//       Republic, The, by Plato
//       Tale of Two Cities, A, by Charles Dickens

Typy struktur refRef struct types

Dodanie modyfikatora ref do deklaracji struct definiuje, że wystąpienia tego typu muszą mieć przydzieloną stos.Adding the ref modifier to a struct declaration defines that instances of that type must be stack allocated. Innymi słowy, wystąpienia tych typów nigdy nie mogą być tworzone na stercie jako element członkowski innej klasy.In other words, instances of these types can never be created on the heap as a member of another class. Podstawowa motywacja tej funkcji była Span<T> i powiązane struktury.The primary motivation for this feature was Span<T> and related structures.

Celem zachowania typu ref struct jako zmiennej przydzieloną stosowo wprowadzono kilka reguł, które kompilator wymusza dla wszystkich typów ref struct.The goal of keeping a ref struct type as a stack-allocated variable introduces several rules that the compiler enforces for all ref struct types.

  • Nie można Box ref struct.You can't box a ref struct. Nie można przypisać typu ref struct do zmiennej typu object, dynamiclub dowolnego typu interfejsu.You cannot assign a ref struct type to a variable of type object, dynamic, or any interface type.
  • typy ref struct nie mogą implementować interfejsów.ref struct types cannot implement interfaces.
  • Nie można zadeklarować ref struct jako elementu członkowskiego pola klasy lub normalnej struktury.You can't declare a ref struct as a field member of a class or a normal struct. Obejmuje to deklarowanie automatycznie zaimplementowanej właściwości, co powoduje utworzenie pola zapasowego wygenerowanego przez kompilator.This includes declaring an auto-implemented property, which creates a compiler generated backing field.
  • Nie można zadeklarować zmiennych lokalnych, które są ref struct typami w metodach asynchronicznych.You cannot declare local variables that are ref struct types in async methods. Można je zadeklarować w metodach synchronicznych, które zwracają Task, Task<TResult> lub Task.You can declare them in synchronous methods that return Task, Task<TResult> or Task-like types.
  • Nie można zadeklarować zmiennych lokalnych ref struct w iteratorach.You cannot declare ref struct local variables in iterators.
  • Nie można przechwytywać zmiennych ref struct w wyrażeniach lambda ani lokalnych funkcjach.You cannot capture ref struct variables in lambda expressions or local functions.

Te ograniczenia uniemożliwiają przypadkowe użycie ref struct w sposób, który mógłby wspierać go w zarządzanym stosie.These restrictions ensure you don't accidentally use a ref struct in a manner that could promote it to the managed heap.

Można połączyć modyfikatory, aby zadeklarować strukturę jako readonly ref.You can combine modifiers to declare a struct as readonly ref. readonly ref struct łączy korzyści i ograniczenia ref struct i readonly struct deklaracji.A readonly ref struct combines the benefits and restrictions of ref struct and readonly struct declarations.

specyfikacja języka C#C# language specification

Aby uzyskać więcej informacji, zobacz Specyfikacja języka C#.For more information, see the C# Language Specification. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.The language specification is the definitive source for C# syntax and usage.

Zobacz takżeSee also