Как сделать свойство ссылочного типа “только для чтения”

Ваш шаблон немного неправильный. Вам нужно экранировать [ и ] и не нужно экранировать @, поскольку @ не является специальным символом в регулярном выражении. Также для захвата содержимого между этими начальным и конечным тегами недостаточно ., поскольку он будет захватывать только один символ, поэтому вам нужно использовать осмотры вокруг и использовать .+? для захвата текста между ними не жадным образом. Попробуйте использовать это регулярное выражение,

(?<=\[@introS\]).+?(?=\[@introEnd@\])

Здесь, (?<=\[@introS\]) положительный взгляд позади гарантирует, что любой текст будет захвачен, предшествует в буквальном смысле [@introS] текст, а затем .+? захватывает любой один или несколько символов как меньше (?=\[@introEnd@\])

Online Demo

и, по возможности, положительный взгляд на будущее [1111]. ] Редактировать: [1130]

В вашем коде было несколько проблем.

  • Ваша декларация регулярного выражения была неправильной, так как строка не была заключена в кавычки, что я уже сказал, и вы исправили.
  • Вам нужно вызвать функцию read() для объекта file, чтобы извлечь строку из файла
  • . Вы можете просто использовать простой findall вместо сопоставления, когда сопоставление работает по-другому и пытается сопоставить полный текст с регулярным выражением
  • Вам нужно было использовать encoding="utf-8" для чтения / записи файла, поскольку файл содержит символы Юникода.

Вот обновленная рабочая копия вашего кода,

import re

def separate_chapters():
 pat = re.compile(r'(?<=\[@introS\]).+?(?=\[@introEnd@\])')
 with open('text1_scott.txt', 'r', encoding="utf-8") as file:
  for i in pat.findall(file.read()):
   print(i)
   inp = input("write text to a file? Y|N: ")
   if inp != "Y":
    continue

   file_name = input("Name of your file: ")

   with open(file_name, "w", encoding="utf-8") as out_file:
     out_file.write(i)
     print("text {} written to a file".format(i))


separate_chapters()

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

11
задан Joel in Gö 26 March 2009 в 09:34
поделиться

7 ответов

Это кажется, что Вы после эквивалента "константы" от C++. Это не существует в C#. Нет никакого способа указать, что потребители не могут изменить свойства объекта, но что-то еще может (предположение, что видоизменяющиеся участники общедоступны, конечно).

Вы могли возвратить клон Нечто, как предложено или возможно представление на Нечто, как ReadOnlyCollection делает для наборов. Конечно, если Вы могли бы сделать Foo неизменный тип, который сделал бы жизнь более простой...

Обратите внимание, что существует большая разница между созданием поля, только для чтения и созданием самого объекта, неизменного.

В настоящее время сам тип мог изменить вещи обоими способами. Это могло сделать:

_Foo = new Foo(...);

или

_Foo.SomeProperty = newValue;

Если это только должно смочь сделать второе, поле могло бы быть только для чтения, но у Вас все еще есть проблема людей, выбирающих способность свойства видоизменить объект. Если это только должно сделать первое, и на самом деле Foo или уже неизменно или мог быть сделан неизменным, можно просто обеспечить свойство, которое только имеет "метод считывания", и Вы будете в порядке.

Очень важно, чтобы Вы поняли различие между изменением значения поля (чтобы заставить его относиться к другому экземпляру) и изменение содержания объекта, к которому относится поле.

11
ответ дан 3 December 2019 в 06:47
поделиться

Если Вы не хотите, чтобы кто-либо смешал с Вашим состоянием... не выставляют его! Как другие сказали, если что-то должно просмотреть Ваше внутреннее состояние, обеспечьте неизменное представление его. С другой стороны, заставьте клиенты говорить Вам делать что-то (Google для "говорят, не спрашивают"), вместо того, чтобы делать его сами.

1
ответ дан 3 December 2019 в 06:47
поделиться

К сожалению, нет никакого простого способа вокруг этого в C# в данный момент. Вы могли извлечь "часть только для чтения" Foo в интерфейсе и позволяют Вашему возврату свойства это вместо Foo.

3
ответ дан 3 December 2019 в 06:47
поделиться

Делая копию, a ReadOnlyCollection, или наличие Foo будьте неизменны, обычно эти три оптимальных маршрута, поскольку Вы уже размышляли.

Я иногда одобряю методы вместо свойств каждый раз, когда я делаю что-либо более значительное, чем простой возврат базового поля, в зависимости от того, сколько работы включено. Методы подразумевают, что что-то продолжается, и повысьте больше флага для потребителей, когда они используют Ваш API.

2
ответ дан 3 December 2019 в 06:47
поделиться

"Клонирование" Foo возражает, что Вы получаете и отдаете, нормальная практика, названная защитным копированием. Если нет некоторый невидимый побочный эффект к клонированию, которое будет видимо пользователю, нет абсолютно никакой причины НЕ сделать это. Это часто - единственный способ защитить внутренние частные данные Ваших классов, особенно в C# или Java, где идея C++ const не доступно. (IE, это должно быть сделано для надлежащего создания действительно неизменных объектов на этих двух языках.)

Просто для уточнения возможные побочные эффекты были бы вещами как Ваш пользователь (обоснованно) ожидающий, что исходный объект быть возвращенным, или некоторый ресурс, сохраненный Foo, который не будет клонирован правильно. (В этом случае, что это делает реализацию IClonable?!)

1
ответ дан 3 December 2019 в 06:47
поделиться

Для разъяснения комментария Jon Skeet, можно сделать представление, которое является неизменным классом обертки для изменяемого Foo. Вот пример:

class Foo{
 public string A{get; set;}
 public string B{get; set;}
 //...
}

class ReadOnlyFoo{
  Foo foo; 
  public string A { get { return foo.A; }}
  public string B { get { return foo.B; }}
}
0
ответ дан 3 December 2019 в 06:47
поделиться

Можно на самом деле воспроизвести поведение константы C++ в C# - просто необходимо сделать это вручную.

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

Например, Foo имеет тип FooClass:

class FooClass
{
    public void MutateMyStateYouBadBoy() { ... }

    public string Message
    {
        get { ... }
        set { ... }
    }
}

Таким образом в Вашем случае, Вы рады за них добраться Message свойство, но не набор это, и Вы определенно не довольны ими называющий тот метод.

Поэтому определите интерфейс, описывающий, что им позволяют сделать:

interface IFooConst
{
    public string Message
    {
        get { ... }
    }
}

Мы не учли метод видоизменения и только уехали в методе считывания на свойстве.

Затем добавьте что интерфейс к основному списку FooClass.

Теперь в Вашем классе с Foo свойство, у Вас есть поле:

private FooClass _foo;

И метод считывания свойства:

public IFooConst Foo
{
    get { return _foo; }
}

Это в основном воспроизводит вручную точно что C++ const ключевое слово сделало бы автоматически. В терминах psuedo-C++, ссылке типа const Foo & похож на автоматически сгенерированный тип, который только включает тех членов Foo это было отмечено как const участники. Переводя это в некоторую теоретическую будущую версию C#, Вы объявили бы FooClass как это:

class FooClass
{
    public void MutateMyStateYouBadBoy() { ... }

    public string Message
    {
        get const { ... }
        set { ... }
    }
}

Действительно все, что я сделал, объединяется информация в IFooConst назад в FooClass, путем меток одного безопасного участника с новым const ключевое слово. Таким образом в некотором смысле, добавление ключевого слова константы не добавило бы много к языку помимо формального подхода к этому шаблону.

Затем, если у Вас был a const ссылка на a FooClass объект:

const FooClass f = GetMeAFooClass();

Вы только смогли бы обратиться к участникам константы f.

Отметьте это если FooClass определение общедоступно, вызывающая сторона могла бросить IFooConst в a FooClass. Но они могут сделать это в C++ также - он отозван, "бросив const"и включает названный специальный оператор const_cast<T>(const T &).

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

0
ответ дан 3 December 2019 в 06:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: