3 changed files with 449 additions and 0 deletions
			
			
		@ -0,0 +1,196 @@ | 
				
			|||||
 | 
					using System; | 
				
			||||
 | 
					using System.Collections; | 
				
			||||
 | 
					using System.Collections.Generic; | 
				
			||||
 | 
					using System.Text; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace Apewer.Models | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    /// <summary>INI 文件。</summary>
 | 
				
			||||
 | 
					    [Serializable] | 
				
			||||
 | 
					    public sealed class IniFile : IEnumerable<IniSection>, IToJson | 
				
			||||
 | 
					    { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        List<IniSection> _sections = new List<IniSection>(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region Constructors
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IniFile() { } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IniFile(IEnumerable<IniSection> sections) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (sections == null) throw new ArgumentNullException(nameof(sections)); | 
				
			||||
 | 
					            sections.ForEach(Add); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region CRUD
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>节的数量。</summary>
 | 
				
			||||
 | 
					        public int Count { get => _sections.Count; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>添加节。</summary>
 | 
				
			||||
 | 
					        public void Add(IniSection section) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (section == null) return; | 
				
			||||
 | 
					            _sections.Add(section); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>添加节。</summary>
 | 
				
			||||
 | 
					        public void Add(string name, TextField[] fields) => _sections.Add(new IniSection(name, fields)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>获取节。</summary>
 | 
				
			||||
 | 
					        public IniSection Get(string sectionName) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var emptyName = sectionName.IsEmpty(); | 
				
			||||
 | 
					            foreach (var section in _sections) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (emptyName) | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    if (section.Name.IsEmpty()) return section; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                else | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    if (section.Name == sectionName) return section; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            return null; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>移除节。</summary>
 | 
				
			||||
 | 
					        public void Remove(IniSection section) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            while (_sections.Contains(section)) _sections.Remove(section); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>移除节。</summary>
 | 
				
			||||
 | 
					        public void Remove(string sectionName) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var emptyName = sectionName.IsEmpty(); | 
				
			||||
 | 
					            foreach (var section in _sections) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (emptyName) | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    _sections = _sections.FindAll(x => x.Name.IsEmpty()); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                else | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    _sections = _sections.FindAll(x => x.Name == sectionName); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region IEnumerable<IniSection>
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IEnumerator<IniSection> GetEnumerator() => new Enumerator<IniSection>(i => i < _sections.Count ? new Class<IniSection>(_sections[i]) : null); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region IToJson
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public Json ToJson() | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var json = Json.NewArray(); | 
				
			||||
 | 
					            _sections.ForEach(section => json.AddItem(section.ToJson())); | 
				
			||||
 | 
					            return json; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region ToString
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const string CRLF = "\r\n"; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public override string ToString() => ToString(CRLF); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public string ToString(string seperator) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (seperator.IsEmpty()) seperator = CRLF; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            var sb = new StringBuilder(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            var noName = 0; | 
				
			||||
 | 
					            foreach (var section in _sections) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (section == null) continue; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                if (section.Name.IsEmpty()) | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    var count = section.Count; | 
				
			||||
 | 
					                    for (var i = 0; i < count; i++) | 
				
			||||
 | 
					                    { | 
				
			||||
 | 
					                        var field = section.GetField(i); | 
				
			||||
 | 
					                        if (Append(sb, field)) | 
				
			||||
 | 
					                        { | 
				
			||||
 | 
					                            sb.Append(seperator); | 
				
			||||
 | 
					                            noName += 1; | 
				
			||||
 | 
					                        } | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            if (noName > 1) sb.Append(seperator); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            foreach (var section in _sections) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (section == null) continue; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                if (section.Name.NotEmpty()) | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    sb.Append("["); | 
				
			||||
 | 
					                    sb.Append(section.Name); | 
				
			||||
 | 
					                    sb.Append("]"); | 
				
			||||
 | 
					                    sb.Append(seperator); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                    foreach (var field in section) | 
				
			||||
 | 
					                    { | 
				
			||||
 | 
					                        if (Append(sb, field)) | 
				
			||||
 | 
					                        { | 
				
			||||
 | 
					                            sb.Append(seperator); | 
				
			||||
 | 
					                        } | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                sb.Append(seperator); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            return sb.ToString(); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        static bool Append(StringBuilder sb, TextField field) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var nameEmpty = field.Name.IsEmpty(); | 
				
			||||
 | 
					            var valueEmpty = field.Value.IsEmpty(); | 
				
			||||
 | 
					            if (nameEmpty && valueEmpty) return false; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            if (!nameEmpty) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                sb.Append(field.Name); | 
				
			||||
 | 
					                sb.Append(" ="); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            if (!valueEmpty) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (nameEmpty) sb.Append("; "); | 
				
			||||
 | 
					                else sb.Append(" "); | 
				
			||||
 | 
					                sb.Append(field.Value); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            return true; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,196 @@ | 
				
			|||||
 | 
					using System; | 
				
			||||
 | 
					using System.Collections; | 
				
			||||
 | 
					using System.Collections.Generic; | 
				
			||||
 | 
					using System.Text; | 
				
			||||
 | 
					using static System.Collections.Specialized.BitVector32; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace Apewer.Models | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    /// <summary>INI 节。</summary>
 | 
				
			||||
 | 
					    [Serializable] | 
				
			||||
 | 
					    public sealed class IniSection : ICollection<TextField>, IEnumerable<TextField>, IToJson | 
				
			||||
 | 
					    { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        private List<TextField> _fields = new List<TextField>(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>节的名称(不含方括号)。</summary>
 | 
				
			||||
 | 
					        public string Name { get; set; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public override string ToString() => $"Name = \"{Name}\", Count = {_fields.Count}"; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region ICollection<TextField>
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public int Count { get => _fields.Count; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>集合是只读的。</summary>
 | 
				
			||||
 | 
					        /// <value>此值始终为 FALSE。</value>
 | 
				
			||||
 | 
					        public bool IsReadOnly { get => false; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>添加字段。</summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        public void Add(TextField item) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (item == null) throw new ArgumentNullException(nameof(item)); | 
				
			||||
 | 
					            _fields.Add(item); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>清空字段。</summary>
 | 
				
			||||
 | 
					        public void Clear() => _fields.Clear(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>检查此集合是否包含指定的字段。</summary>
 | 
				
			||||
 | 
					        public bool Contains(TextField item) => _fields.Contains(item); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>复制字段到数组中。</summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentException" />
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentOutOfRangeException" />
 | 
				
			||||
 | 
					        public void CopyTo(TextField[] array, int arrayIndex) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (array == null) throw new ArgumentNullException(nameof(array)); | 
				
			||||
 | 
					            if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); | 
				
			||||
 | 
					            if (array.Length - arrayIndex < _fields.Count) throw new ArgumentException("目标数组长度不足。"); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            _fields.CopyTo(array, arrayIndex); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>移除字段。</summary>
 | 
				
			||||
 | 
					        public bool Remove(TextField item) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var removed = false; | 
				
			||||
 | 
					            while (_fields.Contains(item)) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                _fields.Remove(item); | 
				
			||||
 | 
					                removed = true; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            return removed; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region Enumerable
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IEnumerator<TextField> GetEnumerator() => new Enumerator<TextField>(i => i < _fields.Count ? new Class<TextField>(_fields[i]) : null); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #region IToJson
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public Json ToJson() | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var fields = Json.NewObject(); | 
				
			||||
 | 
					            foreach (var field in _fields) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                fields.SetProperty(field.Name, field.Value); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            var json = Json.NewObject(); | 
				
			||||
 | 
					            json.SetProperty("name", Name); | 
				
			||||
 | 
					            json.SetProperty("fields", fields); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            return json; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        #endregion
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>检查此集合是否包含指定的字段。</summary>
 | 
				
			||||
 | 
					        /// <param name="name">字段名称。</param>
 | 
				
			||||
 | 
					        public bool Contains(string name) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            var count = _fields.Count; | 
				
			||||
 | 
					            for (var i = 0; i < count; i++) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (_fields[0].Name == name) return true; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            return false; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>获取字段。</summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentOutOfRangeException" />"
 | 
				
			||||
 | 
					        public TextField GetField(int index) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (index < 0 || index >= _fields.Count) throw new ArgumentOutOfRangeException(nameof(index)); | 
				
			||||
 | 
					            return _fields[index]; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public string GetValue(string name) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            foreach (var field in _fields) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (field.Name == name) return field.Value; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            return null; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public void SetValue(string name, string value) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            var count = _fields.Count; | 
				
			||||
 | 
					            var setted = false; | 
				
			||||
 | 
					            for (var i = 0; i < count; i++) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                if (_fields[i].Name == name) | 
				
			||||
 | 
					                { | 
				
			||||
 | 
					                    _fields[i].Value = value; | 
				
			||||
 | 
					                    setted = true; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            if (!setted) | 
				
			||||
 | 
					            { | 
				
			||||
 | 
					                var field = new TextField(name, value); | 
				
			||||
 | 
					                _fields.Add(field); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>获取或设置字段。</summary>
 | 
				
			||||
 | 
					        public string this[string name] { get => GetValue(name); set => SetValue(name, value); } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IniSection() { } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public IniSection(string name) : this() | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            this.Name = name; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        public IniSection(string name, IEnumerable<TextField> fields) : this(name) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (fields == null) throw new ArgumentNullException(nameof(fields)); | 
				
			||||
 | 
					            _fields.AddRange(fields.Map(x => x == null ? null : new TextField(x.Name, x.Value)).FindAll(x => x != null)); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        public IniSection(IEnumerable<TextField> fields) : this(null, fields) { } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        public IniSection(string name, IEnumerable<KeyValuePair<string, string>> fields) : this(name) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (fields == null) throw new ArgumentNullException(nameof(fields)); | 
				
			||||
 | 
					            _fields.AddRange(fields.Map(x => new TextField(x))); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        /// <exception cref="ArgumentNullException" />
 | 
				
			||||
 | 
					        public IniSection(IEnumerable<KeyValuePair<string, string>> fields) : this(null, fields) { } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,57 @@ | 
				
			|||||
 | 
					using System; | 
				
			||||
 | 
					using System.Collections.Generic; | 
				
			||||
 | 
					using System.Text; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace Apewer.Models | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    /// <summary>文本字段。</summary>
 | 
				
			||||
 | 
					    [Serializable] | 
				
			||||
 | 
					    public sealed class TextField | 
				
			||||
 | 
					    { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>名称。</summary>
 | 
				
			||||
 | 
					        public string Name { get; set; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>值。</summary>
 | 
				
			||||
 | 
					        public string Value { get; set; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>文本字段。</summary>
 | 
				
			||||
 | 
					        public TextField() { } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>创建文本字段。</summary>
 | 
				
			||||
 | 
					        public TextField(string name, string value) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            this.Name = name; | 
				
			||||
 | 
					            this.Value = value; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary>创建文本字段。</summary>
 | 
				
			||||
 | 
					        public TextField(KeyValuePair<string, string> pair) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            this.Name = pair.Key; | 
				
			||||
 | 
					            this.Value = pair.Value; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public override string ToString() => $"{Name} = {Value}"; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public override bool Equals(object obj) | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            if (obj != null && obj is TextField field) return field.Name == Name && field.Value == Value; | 
				
			||||
 | 
					            return false; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public override int GetHashCode() => (Name ?? "").GetHashCode() ^ (Value ?? "").GetHashCode(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public static implicit operator KeyValuePair<string, string>(TextField field) => field == null ? default : new KeyValuePair<string, string>(field.Name, field.Value); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        /// <summary></summary>
 | 
				
			||||
 | 
					        public static implicit operator TextField(KeyValuePair<string, string> pair) => new KeyValuePair<string, string>(pair.Key, pair.Value); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue