From 0500b9903e5b7fcdbdc5b3bd0cc9b373779d64d8 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期五, 13 三月 2026 12:47:10 +0800
Subject: [PATCH] feat: implement DB region (Data Blocks)

---
 Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs |  263 ++++++++++++++++++++
 Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs           |  490 +++++++++++++++++++++++++++++++++++++
 2 files changed, 753 insertions(+), 0 deletions(-)

diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs
new file mode 100644
index 0000000..1b72c06
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs
@@ -0,0 +1,490 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using WIDESEAWCS_S7Simulator.Core.Interfaces;
+
+namespace WIDESEAWCS_S7Simulator.Core.Memory
+{
+    /// <summary>
+    /// DB鍖猴紙鏁版嵁鍧楋級- 鏀寔澶氫釜DB鍧�
+    /// </summary>
+    public class DBRegion : IMemoryRegion
+    {
+        /// <summary>
+        /// DB鍧楀瓧鍏革紝閿负DB缂栧彿锛屽�间负瀛楄妭鏁扮粍
+        /// </summary>
+        private readonly Dictionary<ushort, byte[]> _blocks;
+
+        /// <summary>
+        /// 璇诲啓閿侊紙鏀寔骞跺彂璁块棶锛�
+        /// </summary>
+        private readonly ReaderWriterLockSlim _lock;
+
+        /// <summary>
+        /// 閲婃斁鐘舵�佹爣蹇�
+        /// </summary>
+        private bool _disposed = false;
+
+        /// <summary>
+        /// 鍗曚釜DB鍧楃殑澶у皬锛堝瓧鑺傦級
+        /// </summary>
+        private readonly int _blockSize;
+
+        /// <summary>
+        /// 榛樿DB缂栧彿
+        /// </summary>
+        private const ushort DEFAULT_DB_NUMBER = 1;
+
+        /// <summary>
+        /// 鍖哄煙绫诲瀷
+        /// </summary>
+        public string RegionType => "DB";
+
+        /// <summary>
+        /// 鍖哄煙澶у皬锛堝瓧鑺傦級- 杩斿洖榛樿DB鍧楃殑澶у皬
+        /// </summary>
+        public int Size => _blockSize;
+
+        /// <summary>
+        /// 鏋勯�犲嚱鏁�
+        /// </summary>
+        /// <param name="defaultDBNumber">榛樿DB缂栧彿</param>
+        /// <param name="blockSize">鍗曚釜DB鍧楃殑澶у皬</param>
+        public DBRegion(ushort defaultDBNumber, int blockSize)
+        {
+            _blockSize = blockSize;
+            _blocks = new Dictionary<ushort, byte[]>();
+            _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
+
+            // 鍒涘缓榛樿DB鍧�
+            CreateBlock(defaultDBNumber);
+        }
+
+        /// <summary>
+        /// 鍒涘缓DB鍧�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        private void CreateBlock(ushort dbNumber)
+        {
+            if (!_blocks.ContainsKey(dbNumber))
+            {
+                _blocks[dbNumber] = new byte[_blockSize];
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇DB鍧�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <returns>DB鍧楀瓧鑺傛暟缁�</returns>
+        private byte[] GetBlock(ushort dbNumber)
+        {
+            if (!_blocks.ContainsKey(dbNumber))
+            {
+                throw new ArgumentException($"DB鍧椾笉瀛樺湪: DB{dbNumber}");
+            }
+            return _blocks[dbNumber];
+        }
+
+        /// <summary>
+        /// 璇诲彇瀛楄妭鏁版嵁锛堜娇鐢ㄩ粯璁B1锛�
+        /// </summary>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="length">闀垮害</param>
+        /// <returns>瀛楄妭鏁扮粍</returns>
+        public byte[] Read(ushort offset, ushort length)
+        {
+            return Read(DEFAULT_DB_NUMBER, offset, length);
+        }
+
+        /// <summary>
+        /// 璇诲彇瀛楄妭鏁版嵁锛堟寚瀹欴B缂栧彿锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="length">闀垮害</param>
+        /// <returns>瀛楄妭鏁扮粍</returns>
+        public byte[] Read(ushort dbNumber, ushort offset, ushort length)
+        {
+            _lock.EnterReadLock();
+            try
+            {
+                var block = GetBlock(dbNumber);
+                if (offset + length > block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"璇诲彇瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: offset={offset}, length={length}, size={block.Length}");
+                }
+
+                byte[] result = new byte[length];
+                Array.Copy(block, offset, result, 0, length);
+                return result;
+            }
+            finally
+            {
+                _lock.ExitReadLock();
+            }
+        }
+
+        /// <summary>
+        /// 鍐欏叆瀛楄妭鏁版嵁锛堜娇鐢ㄩ粯璁B1锛�
+        /// </summary>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="data">瀛楄妭鏁扮粍</param>
+        public void Write(ushort offset, byte[] data)
+        {
+            Write(DEFAULT_DB_NUMBER, offset, data);
+        }
+
+        /// <summary>
+        /// 鍐欏叆瀛楄妭鏁版嵁锛堟寚瀹欴B缂栧彿锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="data">瀛楄妭鏁扮粍</param>
+        public void Write(ushort dbNumber, ushort offset, byte[] data)
+        {
+            if (data == null)
+            {
+                throw new ArgumentNullException(nameof(data));
+            }
+
+            _lock.EnterWriteLock();
+            try
+            {
+                // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+                if (!_blocks.ContainsKey(dbNumber))
+                {
+                    CreateBlock(dbNumber);
+                }
+
+                var block = _blocks[dbNumber];
+                if (offset + data.Length > block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"鍐欏叆瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: offset={offset}, length={data.Length}, size={block.Length}");
+                }
+
+                Array.Copy(data, 0, block, offset, data.Length);
+            }
+            finally
+            {
+                _lock.ExitWriteLock();
+            }
+        }
+
+        /// <summary>
+        /// 璇诲彇甯冨皵鍊�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="byteOffset">瀛楄妭鍋忕Щ閲�</param>
+        /// <param name="bitOffset">浣嶅亸绉婚噺锛�0-7锛�</param>
+        /// <returns>甯冨皵鍊�</returns>
+        public bool ReadBool(ushort dbNumber, ushort byteOffset, byte bitOffset)
+        {
+            if (bitOffset > 7)
+            {
+                throw new ArgumentOutOfRangeException(nameof(bitOffset), "浣嶅亸绉婚噺蹇呴』鍦�0-7涔嬮棿");
+            }
+
+            _lock.EnterReadLock();
+            try
+            {
+                var block = GetBlock(dbNumber);
+                if (byteOffset >= block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"璇诲彇瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: byteOffset={byteOffset}, size={block.Length}");
+                }
+
+                return (block[byteOffset] & (1 << bitOffset)) != 0;
+            }
+            finally
+            {
+                _lock.ExitReadLock();
+            }
+        }
+
+        /// <summary>
+        /// 鍐欏叆甯冨皵鍊�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="byteOffset">瀛楄妭鍋忕Щ閲�</param>
+        /// <param name="bitOffset">浣嶅亸绉婚噺锛�0-7锛�</param>
+        /// <param name="value">甯冨皵鍊�</param>
+        public void WriteBool(ushort dbNumber, ushort byteOffset, byte bitOffset, bool value)
+        {
+            if (bitOffset > 7)
+            {
+                throw new ArgumentOutOfRangeException(nameof(bitOffset), "浣嶅亸绉婚噺蹇呴』鍦�0-7涔嬮棿");
+            }
+
+            _lock.EnterWriteLock();
+            try
+            {
+                // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+                if (!_blocks.ContainsKey(dbNumber))
+                {
+                    CreateBlock(dbNumber);
+                }
+
+                var block = _blocks[dbNumber];
+                if (byteOffset >= block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"鍐欏叆瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: byteOffset={byteOffset}, size={block.Length}");
+                }
+
+                if (value)
+                {
+                    block[byteOffset] |= (byte)(1 << bitOffset);
+                }
+                else
+                {
+                    block[byteOffset] &= (byte)~(1 << bitOffset);
+                }
+            }
+            finally
+            {
+                _lock.ExitWriteLock();
+            }
+        }
+
+        /// <summary>
+        /// 璇诲彇16浣嶆暣鏁帮紙Int锛屽ぇ绔簭锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <returns>16浣嶆暣鏁�</returns>
+        public short ReadInt(ushort dbNumber, ushort offset)
+        {
+            var data = Read(dbNumber, offset, 2);
+            return (short)((data[0] << 8) | data[1]);
+        }
+
+        /// <summary>
+        /// 鍐欏叆16浣嶆暣鏁帮紙Int锛屽ぇ绔簭锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="value">16浣嶆暣鏁�</param>
+        public void WriteInt(ushort dbNumber, ushort offset, short value)
+        {
+            var data = new byte[2];
+            data[0] = (byte)((value >> 8) & 0xFF);
+            data[1] = (byte)(value & 0xFF);
+            Write(dbNumber, offset, data);
+        }
+
+        /// <summary>
+        /// 璇诲彇32浣嶆暣鏁帮紙DInt锛屽ぇ绔簭锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <returns>32浣嶆暣鏁�</returns>
+        public int ReadDInt(ushort dbNumber, ushort offset)
+        {
+            var data = Read(dbNumber, offset, 4);
+            return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+        }
+
+        /// <summary>
+        /// 鍐欏叆32浣嶆暣鏁帮紙DInt锛屽ぇ绔簭锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="value">32浣嶆暣鏁�</param>
+        public void WriteDInt(ushort dbNumber, ushort offset, int value)
+        {
+            var data = new byte[4];
+            data[0] = (byte)((value >> 24) & 0xFF);
+            data[1] = (byte)((value >> 16) & 0xFF);
+            data[2] = (byte)((value >> 8) & 0xFF);
+            data[3] = (byte)(value & 0xFF);
+            Write(dbNumber, offset, data);
+        }
+
+        /// <summary>
+        /// 璇诲彇32浣嶆诞鐐规暟锛圧eal锛孖EEE 754锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <returns>32浣嶆诞鐐规暟</returns>
+        public float ReadReal(ushort dbNumber, ushort offset)
+        {
+            var data = Read(dbNumber, offset, 4);
+            // 闇�瑕佽浆鎹㈠瓧鑺傚簭锛堝ぇ绔簭杞皬绔簭锛�
+            if (BitConverter.IsLittleEndian)
+            {
+                Array.Reverse(data);
+            }
+            return BitConverter.ToSingle(data, 0);
+        }
+
+        /// <summary>
+        /// 鍐欏叆32浣嶆诞鐐规暟锛圧eal锛孖EEE 754锛�
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="value">32浣嶆诞鐐规暟</param>
+        public void WriteReal(ushort dbNumber, ushort offset, float value)
+        {
+            var data = BitConverter.GetBytes(value);
+            // 闇�瑕佽浆鎹㈠瓧鑺傚簭锛堝皬绔簭杞ぇ绔簭锛�
+            if (BitConverter.IsLittleEndian)
+            {
+                Array.Reverse(data);
+            }
+            Write(dbNumber, offset, data);
+        }
+
+        /// <summary>
+        /// 璇诲彇瀛楃涓诧紙S7瀛楃涓叉牸寮忥級
+        /// S7瀛楃涓叉牸寮忥細[鏈�澶ч暱搴�(1瀛楄妭)][瀹為檯闀垮害(1瀛楄妭)][瀛楃鏁版嵁]
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="maxLength">鏈�澶ч暱搴�</param>
+        /// <returns>瀛楃涓�</returns>
+        public string ReadString(ushort dbNumber, ushort offset, byte maxLength)
+        {
+            _lock.EnterReadLock();
+            try
+            {
+                var block = GetBlock(dbNumber);
+                if (offset + 2 + maxLength > block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"璇诲彇瀛楃涓茶秴鍑篋B{dbNumber}鍖鸿寖鍥�: offset={offset}, maxLength={maxLength}, size={block.Length}");
+                }
+
+                // 璇诲彇瀹為檯闀垮害
+                byte actualLength = block[offset + 1];
+
+                // 璇诲彇瀛楃鏁版嵁
+                if (actualLength == 0)
+                {
+                    return string.Empty;
+                }
+
+                var chars = new char[actualLength];
+                for (int i = 0; i < actualLength; i++)
+                {
+                    chars[i] = (char)block[offset + 2 + i];
+                }
+
+                return new string(chars);
+            }
+            finally
+            {
+                _lock.ExitReadLock();
+            }
+        }
+
+        /// <summary>
+        /// 鍐欏叆瀛楃涓诧紙S7瀛楃涓叉牸寮忥級
+        /// S7瀛楃涓叉牸寮忥細[鏈�澶ч暱搴�(1瀛楄妭)][瀹為檯闀垮害(1瀛楄妭)][瀛楃鏁版嵁]
+        /// </summary>
+        /// <param name="dbNumber">DB缂栧彿</param>
+        /// <param name="offset">鍋忕Щ閲�</param>
+        /// <param name="value">瀛楃涓插��</param>
+        /// <param name="maxLength">鏈�澶ч暱搴�</param>
+        public void WriteString(ushort dbNumber, ushort offset, string value, byte maxLength)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(nameof(value));
+            }
+
+            if (value.Length > maxLength)
+            {
+                throw new ArgumentException(
+                    $"瀛楃涓查暱搴value.Length}瓒呰繃鏈�澶ч暱搴maxLength}");
+            }
+
+            _lock.EnterWriteLock();
+            try
+            {
+                // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+                if (!_blocks.ContainsKey(dbNumber))
+                {
+                    CreateBlock(dbNumber);
+                }
+
+                var block = _blocks[dbNumber];
+                if (offset + 2 + maxLength > block.Length)
+                {
+                    throw new ArgumentOutOfRangeException(
+                        $"鍐欏叆瀛楃涓茶秴鍑篋B{dbNumber}鍖鸿寖鍥�: offset={offset}, maxLength={maxLength}, size={block.Length}");
+                }
+
+                // 鍐欏叆鏈�澶ч暱搴�
+                block[offset] = maxLength;
+
+                // 鍐欏叆瀹為檯闀垮害
+                block[offset + 1] = (byte)value.Length;
+
+                // 鍐欏叆瀛楃鏁版嵁
+                for (int i = 0; i < value.Length; i++)
+                {
+                    block[offset + 2 + i] = (byte)value[i];
+                }
+
+                // 濉厖鍓╀綑绌洪棿涓�0
+                for (int i = value.Length; i < maxLength; i++)
+                {
+                    block[offset + 2 + i] = 0;
+                }
+            }
+            finally
+            {
+                _lock.ExitWriteLock();
+            }
+        }
+
+        /// <summary>
+        /// 娓呯┖鎵�鏈塂B鍧�
+        /// </summary>
+        public void Clear()
+        {
+            _lock.EnterWriteLock();
+            try
+            {
+                foreach (var block in _blocks.Values)
+                {
+                    Array.Clear(block, 0, block.Length);
+                }
+            }
+            finally
+            {
+                _lock.ExitWriteLock();
+            }
+        }
+
+        /// <summary>
+        /// 閲婃斁璧勬簮
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// 閲婃斁璧勬簮
+        /// </summary>
+        /// <param name="disposing">鏄惁姝e湪閲婃斁鎵樼璧勬簮</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    _lock?.Dispose();
+                    _blocks.Clear();
+                }
+                _disposed = true;
+            }
+        }
+    }
+}
diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs
new file mode 100644
index 0000000..6285390
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs
@@ -0,0 +1,263 @@
+using Xunit;
+using WIDESEAWCS_S7Simulator.Core.Memory;
+
+namespace WIDESEAWCS_S7Simulator.UnitTests.Memory
+{
+    public class DBRegionTests
+    {
+        [Fact]
+        public void Constructor_WithValidParameters_CreatesRegion()
+        {
+            // Arrange & Act
+            var region = new DBRegion(1, 1024);
+
+            // Assert
+            Assert.Equal("DB", region.RegionType);
+            Assert.Equal(1024, region.Size);
+        }
+
+        [Fact]
+        public void Read_ValidDBNumberAndOffset_ReturnsData()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            var testData = new byte[] { 0x12, 0x34, 0x56, 0x78 };
+            region.Write(1, 0, testData);
+
+            // Act
+            var result = region.Read(1, 0, 4);
+
+            // Assert
+            Assert.Equal(testData, result);
+        }
+
+        [Fact]
+        public void Read_InvalidDBNumber_ThrowsArgumentException()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act & Assert
+            Assert.Throws<ArgumentException>(() => region.Read(999, 0, 4));
+        }
+
+        [Fact]
+        public void Read_OutOfBounds_ThrowsArgumentOutOfRange()
+        {
+            // Arrange
+            var region = new DBRegion(1, 100);
+
+            // Act & Assert
+            Assert.Throws<ArgumentOutOfRangeException>(() => region.Read(1, 0, 101));
+        }
+
+        [Fact]
+        public void Write_MultipleDBs_StoresSeparately()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            var data1 = new byte[] { 0x11, 0x22, 0x33, 0x44 };
+            var data2 = new byte[] { 0xAA, 0xBB, 0xCC, 0xDD };
+
+            // Act
+            region.Write(1, 0, data1);
+            region.Write(2, 0, data2);
+            var result1 = region.Read(1, 0, 4);
+            var result2 = region.Read(2, 0, 4);
+
+            // Assert
+            Assert.Equal(data1, result1);
+            Assert.Equal(data2, result2);
+        }
+
+        [Fact]
+        public void Clear_AllBlocks_ZerosAllMemory()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0xFF, 0xFF, 0xFF });
+            region.Write(2, 0, new byte[] { 0xAA, 0xBB, 0xCC });
+
+            // Act
+            region.Clear();
+            var result1 = region.Read(1, 0, 3);
+            var result2 = region.Read(2, 0, 3);
+
+            // Assert
+            Assert.Equal(new byte[] { 0, 0, 0 }, result1);
+            Assert.Equal(new byte[] { 0, 0, 0 }, result2);
+        }
+
+        [Fact]
+        public void ReadInt_ValidOffset_ReturnsCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0x12, 0x34 }); // S7 Int: 0x1234 = 4660
+
+            // Act
+            var result = region.ReadInt(1, 0);
+
+            // Assert
+            Assert.Equal(4660, result);
+        }
+
+        [Fact]
+        public void WriteInt_ValidOffset_WritesCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act
+            region.WriteInt(1, 0, 4660); // 0x1234
+            var result = region.Read(1, 0, 2);
+
+            // Assert
+            Assert.Equal(new byte[] { 0x12, 0x34 }, result);
+        }
+
+        [Fact]
+        public void ReadDInt_ValidOffset_ReturnsCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0x00, 0x01, 0x00, 0x00 }); // S7 DInt: 65536
+
+            // Act
+            var result = region.ReadDInt(1, 0);
+
+            // Assert
+            Assert.Equal(65536, result);
+        }
+
+        [Fact]
+        public void WriteDInt_ValidOffset_WritesCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act
+            region.WriteDInt(1, 0, 65536); // 0x00010000
+            var result = region.Read(1, 0, 4);
+
+            // Assert
+            Assert.Equal(new byte[] { 0x00, 0x01, 0x00, 0x00 }, result);
+        }
+
+        [Fact]
+        public void ReadReal_ValidOffset_ReturnsCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0x41, 0x20, 0x00, 0x00 }); // IEEE 754: 10.0f
+
+            // Act
+            var result = region.ReadReal(1, 0);
+
+            // Assert
+            Assert.Equal(10.0f, result);
+        }
+
+        [Fact]
+        public void WriteReal_ValidOffset_WritesCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act
+            region.WriteReal(1, 0, 10.0f);
+            var result = region.Read(1, 0, 4);
+
+            // Assert
+            Assert.Equal(new byte[] { 0x41, 0x20, 0x00, 0x00 }, result);
+        }
+
+        [Fact]
+        public void ReadBool_ValidOffset_ReturnsCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0xFF }); // 鎵�鏈変綅涓�1
+
+            // Act
+            var result = region.ReadBool(1, 0, 3);
+
+            // Assert
+            Assert.True(result);
+        }
+
+        [Fact]
+        public void WriteBool_ValidOffset_SetsCorrectValue()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act
+            region.WriteBool(1, 0, 3, true);
+            var result = region.ReadBool(1, 0, 3);
+
+            // Assert
+            Assert.True(result);
+        }
+
+        [Fact]
+        public void ReadString_WriteAndReadString_ReturnsOriginalString()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            var testString = "Hello";
+
+            // Act
+            region.WriteString(1, 0, testString, 10);
+            var result = region.ReadString(1, 0, 10);
+
+            // Assert
+            Assert.Equal(testString, result);
+        }
+
+        [Fact]
+        public void ReadString_EmptyString_ReturnsEmptyString()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+
+            // Act
+            region.WriteString(1, 0, "", 10);
+            var result = region.ReadString(1, 0, 10);
+
+            // Assert
+            Assert.Equal("", result);
+        }
+
+        [Fact]
+        public void ReadString_StringWithMaxLength_RespectsMaxLength()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            var testString = "ABC";
+
+            // Act
+            region.WriteString(1, 0, testString, 5);
+            var result = region.ReadString(1, 0, 5);
+
+            // Assert
+            Assert.Equal(testString, result);
+        }
+
+        [Fact]
+        public void Dispose_ClearsBlocksDictionary()
+        {
+            // Arrange
+            var region = new DBRegion(1, 1024);
+            region.Write(1, 0, new byte[] { 0x12, 0x34 });
+            region.Write(2, 0, new byte[] { 0x56, 0x78 });
+
+            // Act
+            region.Dispose();
+
+            // Assert - trying to access after dispose should handle gracefully
+            // The implementation should clear the dictionary
+            Assert.True(true); // If no exception thrown, test passes
+        }
+    }
+}

--
Gitblit v1.9.3