2008-11-10 3 views
199

Каковы преимущества наличия переменной-члена, объявленной как только для чтения? Является ли это просто защитой от кого-либо, изменяющегося в течение жизненного цикла класса, или есть какие-либо улучшения скорости компилятора из-за этого ключевого словаВ чем преимущества маркировки поля как `readonly` в C#?

+5

Хороший внешний ответ: http://www.dotnetperls.com/readonly – OneWorld 2012-02-28 19:48:30

+1

Интересно. Это, по сути, эквивалент C# этого Java-вопроса. Http://stackoverflow.com/questions/137868/using-final-modifier-whenever-applicable-in-java Обсуждение здесь гораздо менее нагрето, хотя ... hmm ... – RAY 2012-04-24 09:28:08

+5

Возможно, стоит заметить, что поля `readonly` типов структуры налагают штраф за производительность по сравнению с изменяемыми полями, которые просто не мутируются, поскольку вызов любого члена поля типа read readlyly приведет к компилятору сделать копию поля и вызвать участника на этом. – supercat 2012-10-28 01:22:33

ответ

89

Ключевое слово readonly используется для объявления переменной-члена константой, но позволяет вычислять значение во время выполнения , Это отличается от константы, объявленной с помощью модификатора const, который должен иметь значение, установленное во время компиляции. Используя readonly, вы можете установить значение поля либо в объявлении, либо в конструкторе объекта, членом которого является поле.

Также используйте его, если вы не хотите перекомпилировать внешние DLL, которые ссылаются на константу (поскольку она заменяется во время компиляции).

+3

Пока я не оспариваю определение, я думаю, из вопроса, что ak, вероятно, понимает разницу между ними. Сравнение двух было бы спорным - у одного нет преимущества перед другим - они используются в разных обстоятельствах (как я уверен, вы хорошо знаете). – Xiaofu 2008-11-11 03:53:28

+72

Я не понимаю, почему этот вопрос был отмечен как ответ. Это не отвечает на вопрос. Вопрос был не в том, что такое diff между const и readonly - он спросил, зачем его использовать? – 2009-01-29 17:52:38

+4

Кто-то другой отредактировал вопрос почти через две недели после того, как OP принял мой ответ. По-видимому, ОП почувствовал, что его первоначальный вопрос был дан. – 2009-01-29 18:13:22

56

Нет никаких очевидных преимуществ при использовании readonly, по крайней мере, того, что я когда-либо видел, упоминалось где-либо. Это просто для того, чтобы делать то, что вы предлагаете, для предотвращения модификации после его инициализации.

Таким образом, это выгодно тем, что оно поможет вам написать более надежный, более читаемый код. Настоящая выгода таких вещей возникает, когда вы работаете в команде или для обслуживания. Объявление чего-то readonly сродни заключению контракта на использование этой переменной в коде. Подумайте об этом, добавив документацию так же, как и другие ключевые слова, такие как internal или private, вы говорите: «эту переменную не следует изменять после инициализации», и, кроме того, вы используете , применяя.

Итак, если вы создаете класс и отмечаете некоторые переменные-члены readonly по дизайну, то вы предотвращаете себя или другого члена команды, допустившего ошибку позже, когда они расширяются или изменяют ваш класс. На мой взгляд, это преимущество, которое стоит (при небольшом расходе дополнительной языковой сложности, как указано в комментариях).

146

Я не верю, что есть какие-либо выгоды от использования поля readonly. Это просто проверка, чтобы убедиться, что как только объект будет полностью построен, это поле не может быть указано на новое значение.

Однако «readonly» сильно отличается от других типов семантики только для чтения, поскольку она применяется во время выполнения CLR. Ключевое слово readonly скомпилировано до .initonly, которое проверяется CLR.

Настоящим преимуществом этого ключевого слова является создание неизменяемых структур данных. Неизменяемые структуры данных по определению не могут быть изменены после их создания. Это позволяет легко рассуждать о поведении структуры во время выполнения. Например, нет никакой опасности передать неизменяемую структуру другой случайной части кода. Они не могут изменить его, чтобы вы могли надежно запрограммировать эту структуру.

Вот хорошая запись об одном из преимуществ неизменности: Threading

33

Для того, чтобы поставить его в практическом плане:

Если вы используете константный в ссылках длл А и длл В том, что Const, то значение этой константы будет скомпилировано в dll B. Если вы повторно развернете dll A с новым значением для этого const, dll B все равно будет использовать исходное значение.

Если вы используете readonly в ссылках dll A и dll B, которые только для чтения, то, что readonly всегда будет проверяться во время выполнения. Это означает, что если вы повторно развернете dll A с новым значением для этого только для чтения, dll B будет использовать это новое значение.

5

Имейте в виду, что readonly применяется только к самому значению, поэтому, если вы используете ссылочный тип, только для чтения только защищает ссылку от изменения. Состояние экземпляра не защищено readonly.

1

Будьте осторожны с частными массивами readonly. Если они подвергаются клиенту как объекту (вы можете сделать это для COM-взаимодействия, как и я), клиент может манипулировать значениями массива. Используйте метод Clone() при возврате массива в качестве объекта.

9

Существует потенциальный случай, когда компилятор может сделать оптимизацию производительности на основе наличия ключевого слова readonly.

Это применимо, если поле readonly также отмечено как статическое. В этом случае компилятор JIT может предположить, что это статическое поле никогда не изменится. Компилятор JIT может учитывать это при компиляции методов класса.

Типичный пример: ваш класс может иметь статическое readonly Поле IsDebugLoggingEnabled, которое инициализируется в конструкторе (например, на основе файла конфигурации). После того, как фактические методы скомпилированы JIT, компилятор может исключить целые части кода, когда ведение журнала отладки не включено.

Я не проверял, действительно ли эта оптимизация реализована в текущей версии JIT-компилятора, поэтому это всего лишь предположение.

4

Не забудьте обходное решение, чтобы получить поля readonly вне любых конструкторов, используя параметры out.

Немного грязный, но:

private readonly int _someNumber; 
private readonly string _someText; 

public MyClass(int someNumber) : this(data, null) 
{ } 

public MyClass(int someNumber, string someText) 
{ 
    Initialise(out _someNumber, someNumber, out _someText, someText); 
} 

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText) 
{ 
    //some logic 
} 

Дальнейшее обсуждение здесь: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx

0

Там может быть выигрыш в производительности в WPF, поскольку он устраняет необходимость в дорогостоящих DependencyProperties. Это может быть особенно полезно с коллекциями

0

Еще одна интересная часть использования маркировки только для чтения может защищать поле от инициализации в одноэлементном режиме.

, например, в коде из csharpindepth:

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton()); 

    public static Singleton Instance { get { return lazy.Value; } } 

    private Singleton() 
    { 
    } 
} 

играет небольшую только для чтения роль защиты от поля Singleton инициализации дважды. Другая деталь заключается в том, что для упомянутого сценария вы не можете использовать const, потому что const заставляет создавать во время компиляции, но singleton делает создание во время выполнения.

1

Если у вас есть предварительно определенное или предварительно рассчитанное значение, которое должно оставаться таким же в программе, тогда вы должны использовать константу, но если у вас есть значение, которое должно быть предоставлено во время выполнения, но после того, как назначенный должен оставаться таким же на протяжении всей программа u должна использовать readonly. например, если вам нужно назначить время начала программы или вам нужно сохранить предоставленное пользователем значение при инициализации объекта, и вы должны ограничить его из дальнейших изменений, вы должны использовать только для чтения.

2

readonly может быть инициализирован при объявлении или получить его значение только от конструктора. В отличие от const, он должен быть инициализирован и объявлен одновременно. readonlyимеет всеconstимеет, а также конструктор инициализации

кодhttps://repl.it/HvRU/1

using System; 

class MainClass { 
    public static void Main (string[] args) { 

     Console.WriteLine(new Test().c); 
     Console.WriteLine(new Test("Constructor").c); 
     Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
     // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
     // variable initializer) 
    } 


    public class Test { 
     public readonly string c = "Hello World"; 
     public Test() { 

     } 

     public Test(string val) { 
      c = val; 
     } 

     public string ChangeC() { 
      c = "Method"; 
      return c ; 
     } 
    } 
}