C# 类属性“绑定”到文件? (见 Perl::Tie)

Posted

技术标签:

【中文标题】C# 类属性“绑定”到文件? (见 Perl::Tie)【英文标题】:C# Class Properties 'tied' to a file? (See Perl::Tie) 【发布时间】:2017-06-24 05:35:37 【问题描述】:

在 perl 中有一个相当简单的方法将数据结构绑定到文件,无论是字符串、哈希(C# 中的字典)还是简单的数组/列表。

我在 C# 中拼凑了自己的半途而废的解决方案,但我想知道是否有更内置的方法来实现此功能?

编辑以回应下面的评论 - 直接问题:是否有一种内置方法可以将类/字典“绑定”到文件,以便其中任何一个中的任何更改都反映在另一个中? (没有像我在下面所做的那样)

(绑定字典意味着字典中的任何更改都会立即反映/更新到文件中,如果对象已经存在,则声明绑定的 var 从磁盘加载对象;请参阅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();
        

【问题讨论】:

那么问题是什么?代码与这个问题相关吗? 我的代码是我所追求的一个冗长的例子。我正在寻找的,具体来说,是将结构与磁盘上的文件联系起来的内置 .NET 方式. (另外,将代码留给正在寻找此功能的其他人,因为它可能对其他人有用。) 绑定散列是为对象提供散列的接口。在 C# 中,字典是对象,因此您只需创建一个实现 IDictionary 的类。 【参考方案1】:

我想您正在寻找一种将类实例存储在文件中的简单方法。

序列化是将对象转换为字节流以存储对象或将其传输到内存、数据库或文件的过程。它的主要目的是保存对象的状态,以便能够在需要时重新创建它。逆过程称为反序列化。

不久前我为 C# here 找到的最短解决方案是来自 Newtonsoft 的 Json.NET,它以 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

【讨论】:

我知道序列化并试图避免它。它与我已经在做的没有太大的不同,这是我不想要的。我正在尝试获取磁盘上存在的活动对象,并且任何访问基本上都重定向到存储在磁盘上的对象。不需要我每次更新对象时都调用 Object.Serialize(file, etc)。所以简而言之,我猜没有本机(例如,没有外部库)方法来实现这一点? 听起来类似于内存映射文件。试试这个:another *** answer 我没有考虑过使用 MMF,但根据我自己有限的经验,我不确定它是否会产生与我想要实现的功能完全相同的功能,但我会提供还是去吧。如果你有时间,你能用一个例子更新你的答案吗? @MisterNad MSDN 可以为您提供比我更多的代码示例。我只是在尝试构建从 C++ 应用程序到 C# 应用程序的可靠内存交换时阅读有关 MMF 的内容。我最终得到了一个使用进程间内存读取的解决方案,而不使用文件。 @MisterNad 如果您不需要经常更改磁盘存储 - 我想编写一个类将您的活动对象与文件同步如果(它被更改并且偶尔,说一次一秒钟)将减少耗时。

以上是关于C# 类属性“绑定”到文件? (见 Perl::Tie)的主要内容,如果未能解决你的问题,请参考以下文章

C# datagridview列绑定类中类的属性

c# 中如何把实体类绑定到dataGridView并显示出来。

C# winforms:将可空类型绑定到其他属性(不是文本)时出错

绑定:如何绑定另一个类的属性

c# dataGridView控件里面的DataSource这个属性问题

C#如何在没有 XAML 的情况下创建到父元素的(两种方式)数据绑定