Свойства класса C # привязаны к файлу? (См. Perl :: Tie)

В perl есть довольно простой метод привязки структуры данных к файлу, будь то строка, хэш (словарь в C #) или простой массив / список.

Я сколотил свое собственное недоработанное решение на C #, но мне было интересно, есть ли более встроенный способ достижения этой функциональности?

Изменить в ответ на комментарий ниже - Вопрос напрямую: есть ли встроенный способ «привязать» класс / словарь к файлу, чтобы любые изменения в одном из них отражались в другом? (Не делая того, что я сделал ниже)

(Связывание словаря означает, что любые изменения в словаре немедленно отражаются / обновляются в файле, а объявление связанной переменной загружает объект с диска, если он уже существует; см. PerlTie)

Мой псевдо-связанный класс ниже:

    #region options
    private float _Opacity;
    public float Opacity {
        get {
            return Opacity;
            }
        set {
            _Opacity = value;
            this.Save();
            }
        }

    private Font _Font;
    public Font Font {
        get {
            return _Font;
            }
        set {
            _Font = value;
            this.Save();
            }
        }

    private Color _FontColor;
    public Color FontColor {
        get {
            return _FontColor;
            }
        set {
            _FontColor = value;
            this.Save();
            }
        }

    private Color _BGColor;
    public Color BGColor {
        get {
            return _BGColor;
            }
        set {
            _BGColor = value;
            this.Save();
            }
        }

    private Point _Location;
    public Point Location {
        get {
            return _Location;
            }
        set {
            _Location = value;
            this.Save();
            }
        }

    private Size _Size;
    public Size Size {
        get {
            return _Size;
            }
        set {
            _Size = value;
            this.Save();
            }
        }

    private ushort _HistoryLines;
    public ushort HistoryLines {
        get {
            return _HistoryLines;
            }
        set {
            _HistoryLines = value;
            this.Save();
            }
        }

    private ChatType _ChatModes;
    public ChatType ChatModes {
        get {
            return _ChatModes;
            }
        set {
            _ChatModes = value;
            this.Save();
            }
        }

    private bool _Debugging;
    public bool Debugging {
        get {
            return _Debugging;
            }
        set {
            _Debugging = value;
            this.Save();
            }
        }
    #endregion options

    private FontConverter FontConvert;
    private FileInfo SettingsFile;

    private MLogConf() {
        }

    public MLogConf(string stateFile) {
        FontConvert = new FontConverter();
        try {

            if (!Directory.Exists(Path.GetDirectoryName(stateFile)))
                Directory.CreateDirectory(Path.GetDirectoryName(stateFile));
            if (!File.Exists(stateFile)) {
                FileStream fs = File.Create(stateFile);
                fs.Close();
                }
            SettingsFile = new FileInfo(stateFile);
            if (SettingsFile.Length == 0) {
                this.SetDefaultOptions();
                } else {
                if (!this.Load()) {
                    throw new FileLoadException("Couldn't load settings file");
                    }
                }
            } catch (Exception ex) {
            Trace.Write($"Failed to create MLogConf({nameof(stateFile)}) {ex.Message + Environment.NewLine + ex.StackTrace}");
            }
        }

    private bool Load() {
        if (SettingsFile == null)
            return false;
        try {
            byte[] data = File.ReadAllBytes(SettingsFile.FullName);
            using (MemoryStream m = new MemoryStream(data)) {
                using (BinaryReader reader = new BinaryReader(m)) {
                    _Opacity = reader.ReadSingle();
                    _Font = (Font)(FontConvert.ConvertFromString(Encoding.ASCII.GetString(Convert.FromBase64String(reader.ReadString()))));
                    _FontColor = Color.FromArgb(reader.ReadInt32());
                    _BGColor = Color.FromArgb(reader.ReadInt32());
                    _Location = new Point(reader.ReadInt32(), reader.ReadInt32());
                    _Size = new Size(reader.ReadInt32(), reader.ReadInt32());
                    _HistoryLines = reader.ReadUInt16();
                    _ChatModes = (ChatType)reader.ReadInt32();
                    _Debugging = reader.ReadBoolean();
                    }
                }
            } catch (Exception e) {
            Trace.WriteLine($"Exception reading binary data: {e.Message + Environment.NewLine + e.StackTrace}");
            return false;
            }
        return true;
        }

    private bool Save() {
        try {
            using (FileStream fs = new FileStream(SettingsFile.FullName, FileMode.Create)) {
                using (BinaryWriter writer = new BinaryWriter(fs)) {
                    writer.Write(_Opacity);
                    writer.Write(Convert.ToBase64String(Encoding.ASCII.GetBytes((string)FontConvert.ConvertTo(Font, typeof(string)))));
                    writer.Write(_FontColor.ToArgb());
                    writer.Write(_BGColor.ToArgb());
                    writer.Write(_Location.X);
                    writer.Write(_Location.Y);
                    writer.Write(_Size.Width);
                    writer.Write(_Size.Height);
                    writer.Write(_HistoryLines);
                    writer.Write((int)_ChatModes);
                    writer.Write(_Debugging);
                    }
                }
            } catch (Exception e) {
            Trace.WriteLine($"Exception writing binary data: {e.Message + Environment.NewLine + e.StackTrace}");
            return false;
            }
        return true;
        }


    private bool SetDefaultOptions() {
        this._BGColor = Color.Black;
        this._ChatModes = ChatType.Alliance | ChatType.Emote | ChatType.FreeCompany | ChatType.Linkshell | ChatType.Party | ChatType.SayShoutYell | ChatType.Tell;
        this._Opacity = 1f;
        this._Font = new Font("Verdana", 50);
        this._FontColor = Color.CornflowerBlue;
        this._Location = new Point(100, 400);
        this._Size = new Size(470, 150);
        this._HistoryLines = 512;
        this._Debugging = false;
        return this.Save();
        }

person MisterNad    schedule 24.06.2017    source источник
comment
Так в чем вопрос? Соответствует ли код этому вопросу?   -  person user2864740    schedule 24.06.2017
comment
Мой код - это длинный пример того, что мне нужно. В частности, я ищу встроенный в .NET способ привязки структуры к файлу на диске. (Кроме того, оставьте код для всех, кто ищет эту функцию, поскольку она может оказаться полезной для других.)   -  person MisterNad    schedule 24.06.2017
comment
Связывание хеша - это предоставление объекту интерфейса хеша. В C # словари являются объектами, поэтому вы просто создаете класс, реализующий IDictionary.   -  person ikegami    schedule 24.06.2017


Ответы (1)


Я полагаю, вы ищете простой способ хранить экземпляры классов в файлах.

Сериализация - это процесс преобразования объекта в поток байтов, чтобы сохранить объект или передать его в память, базу данных или файл. Его основная цель - сохранить состояние объекта, чтобы иметь возможность воссоздать его при необходимости. Обратный процесс называется десериализацией.

Самое короткое решение, которое я нашел для C #, здесь некоторое время назад был Json.NET от Newtonsoft, доступный как пакет NuGet. Он выполнит за вас весь «длинный код свойства класса в строку» и оставит вам строку, готовую для записи в файл. Официальный сайт может предоставить примеры кода: http://www.newtonsoft.com/json

Сохранить в файл:

Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };

string json = JsonConvert.SerializeObject(product);
// {
//   "Name": "Apple",
//   "Expiry": "2008-12-28T00:00:00",
//   "Sizes": [
//     "Small"
//   ]
// }

Прочитать из файла:

string json = @"{
  'Name': 'Bad Boys',
  'ReleaseDate': '1995-4-7T00:00:00',
  'Genres': [
    'Action',
    'Comedy'
  ]
}";

Movie m = JsonConvert.DeserializeObject<Movie>(json);

string name = m.Name;
// Bad Boys
person Andrew Myhalchuk    schedule 24.06.2017
comment
Я знаю о сериализации и пытался ее избежать ... Это не сильно отличается от того, что я уже делаю, чего я не хочу. Я пытаюсь получить живой объект, который существует на диске, и любой доступ по существу перенаправляется на объект, хранящийся на диске. Не требуя от меня вызова Object.Serialize (файл и т. Д.) Каждый раз, когда объект обновляется. Короче говоря, я предполагаю, что нет собственного (например, внешних библиотек) способа сделать это? - person MisterNad; 24.06.2017
comment
Похоже на файл с отображением памяти. Попробуйте следующее: другой ответ на stackoverflow - person Andrew Myhalchuk; 24.06.2017
comment
Я не рассматривал возможность использования MMF, хотя, исходя из моего ограниченного опыта, я не уверен, что он будет обеспечивать ту же функциональность, которую я пытаюсь достичь, но, тем не менее, я попробую. Не могли бы вы дополнить свой ответ примером, если у вас есть время? - person MisterNad; 24.06.2017
comment
@MisterNad MSDN может дать вам больше примеров кода, чем я. Я только что читал о MMF, пытаясь создать надежный обмен памятью из приложения C ++ в приложение C #. Я пришел к решению, использующему межпроцессное чтение памяти без использования файлов. - person Andrew Myhalchuk; 24.06.2017
comment
@MisterNad В случае, если вам не требуется очень часто менять дисковое хранилище - я думаю, написание класса, который синхронизирует ваш живой объект с файлом, если (он был изменен и время от времени, скажем, один раз в секунду) будет меньше времени - потребляющий. - person Andrew Myhalchuk; 24.06.2017
comment
Это постоянное хранилище для размещения окна и различных связанных с ним опций, поэтому оно не будет часто обновляться. Это состояние сохранения окна, поэтому пользователю не нужно заново настраивать параметры окна / чата каждый раз, когда они запустите приложение. (Это инструмент автоматического перевода для MMO, JP- ›EN перевод. Он находится в верхней части игры (и скрывает панель задач) с настраиваемой непрозрачностью, переходом по щелчку и имеет общесистемные горячие клавиши) Вот почему я бы хотел параметры должны быть активными, они изменяются на лету, так что, если программа неожиданно завершает работу, параметры все еще остаются в силе для следующего запуска. - person MisterNad; 24.06.2017
comment
Поскольку вы не опубликовали еще один ответ в соответствии с тем, что я искал, я просто приму этот ответ и продолжу использовать метод, который я опубликовал в OP .. Спасибо за ваши ответы, Эндрю :) - person MisterNad; 24.06.2017