C# - Nestable,有界数组

本文关键字:数组 Nestable | 更新日期: 2023-09-27 18:37:08

我正在将一个用Pascal编写的游戏(用16位编译)移植到C#(因此它将在比XP更新的机器上运行)。 根据我收集的信息,在 Pascal 中,可以通过这样的语法在单元/程序的类型部分中键入定义:

type
    BaseArrayPtr = ^BaseArray;
    BaseArray = array [1 .. 5, 1 .. 5] of Integer;
    SubArray = array [0 .. 3] of BaseArray;

我还收集到,不幸的是,不可能在 C# 中键入定义。 但是,我正在尝试解决方法。 到目前为止,这就是我所拥有的:

有界数组.cs:

using System;
using System.Collections;
namespace test
{
    abstract class BoundedArray<T>
    {
        public BoundedArray()
        {
            m_data = null;
        }
        public T this[params int[] index]
        {
            get
            {
                if (index.Length != m_data.Rank)
                    throw new IndexOutOfRangeException();
                return (T) m_data.GetValue(index);
            }
            set
            {
                if (index.Length != m_data.Rank)
                    throw new IndexOutOfRangeException();
                m_data.SetValue(value, index);
            }
        }
        protected void SetAttributes(int[] lowerBounds, int[] lengths)
        {
            if (lengths.Length != lowerBounds.Length)
                throw new ArgumentException();
            m_lowerBounds = lowerBounds;
            m_lengths = lengths;
            m_data = Array.CreateInstance(typeof(T), m_lengths, m_lowerBounds);
            m_data.Initialize(); // Should (but doesn't) initialize every element in m_data
        }
        Array m_data;
        int[] m_lengths;
        int[] m_lowerBounds;
    }
}

测试.cs:

using System;
namespace test
{
    class Program
    {
        public static int[] ints(params int[] values)
        {
            return values;
        }
        class BaseArray : BoundedArray<int>
        {
            public BaseArray()
            {
                SetAttributes(ints(2, 2), ints(1, 2));
            }
        }
        class SubArray : BoundedArray<BaseArray>
        {
            public SubArray()
            {
                SetAttributes(ints(4), ints(2));
            }
        }
        static void Main(string[] args)
        {
            SubArray subArray = new SubArray();
            Console.Read();
        }
    }
}

我已经检查了baseArraym_data的默认值为零,因为它们是int s。 但是,在 subArray 中,m_data 的默认值为 null - 由于某种原因,数组内的 BaseArray 个实例subArray尚未初始化。 如何让默认构造函数运行?

编辑:目前真正的问题是为什么SetAttributes方法中的m_data.Initialize();不初始化m_data中的所有元素? MSDN上的文档似乎表明它应该...

编辑:所以我认为问题在于System.Array.Initialize只适用于值类型。 由于类是 C# 中的引用类型,因此System.Array.Initialize不执行任何操作。 所以我必须找到一种方法来初始化一个可变维度、长度和下限的引用类型数组。

C# - Nestable,有界数组

好吧,我已经做了一些更改,当您要创建SubArray的实例时,您应该传递BaseArray作为要初始化的数据源。

据我了解,您希望将值从 BaseArray 设置为 SubArray.

这是我的工作:

有界数组.cs

 abstract class BoundedArray<T>
{
    public BoundedArray()
    {
        m_data = null;
    }
    public int[] Lengths;
    public int[] LowerBounds;
    public void CreateInstance()
    {
        if (Lengths.Length != LowerBounds.Length)
            throw new Exception("Incorrect number of lengths or lower bounds.");
        m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
    }
    public void CreateInstance(Array source)
    {
        if (Lengths.Length != LowerBounds.Length)
            throw new Exception("Incorrect number of lengths or lower bounds.");
        m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
        /************************************************************************/
        /*    Now you should find the value of BaseArray and set it to m_data                                                                     */
        /************************************************************************/

    }
    public T this[params int[] index]
    {
        get
        {
            if (index.Length != m_data.Rank)
                throw new IndexOutOfRangeException();
            return (T)m_data.GetValue(index);
        }
        set
        {
            if (index.Length != m_data.Rank)
                throw new IndexOutOfRangeException();
            m_data.SetValue(value, index);
        }
    }
    public Array GetData()
    {
        return m_data;
    }
    Array m_data;
}

测试.cs

class Program
{
    public static int[] ints(params int[] values)
    {
        return values;
    }
    class BaseArray : BoundedArray<int>
    {
        public BaseArray()
        {
            Lengths = ints(1, 2);
            LowerBounds = ints(2, 2);
            CreateInstance();
        }
    }
    class SubArray : BoundedArray<BaseArray>
    {
        public SubArray(BaseArray arr)
        {
            Lengths = ints(2);
            LowerBounds = ints(4);
            CreateInstance(arr.GetData());
        }
    }
    static void Main(string[] args)
    {
        BaseArray baseArray = new BaseArray();
        SubArray subArray = new SubArray(baseArray);
        Console.Read();
    }
}

你有一个单维数组SubArray它包含BaseArray对象,这些对象是交互器的二维数组。代替 Pascal type ,您可以定义一个自定义 C# 类,该类将覆盖索引器运算符以提供完全相同的行为。

编辑所以,在帕斯卡中你有这个:

type
    BaseArrayPtr = ^BaseArray;
    BaseArray = array [1 .. 5, 1 .. 5] of Integer;
    SubArray = array [0 .. 3] of BaseArray;

也许我误解了这个问题,但是在 C# 中,下面的内容不完全相同吗?

public class BaseArray
{
    int[,] m_array = new int[5, 5];
    static void CheckBounds(int x, int y)
    {
        if (x < 1 || x > 5 || y < 1 || y > 5)
            throw new IndexOutOfRangeException();
    }
    public int this[int x, int y]
    {
        get 
        {
            CheckBounds(x, y);
            return m_array[x-1, y-1]; 
        }
        set 
        {
            CheckBounds(x, y);
            m_array[x-1, y-1] = value; 
        }
    }
}
public class SubArray
{
    BaseArray[] m_array = new BaseArray[4];
    public BaseArray this[int x]
    {
        get { return m_array[x]; }
        set { m_array[x] = value; }
    }
}

我已经回答过一次我自己的问题,但我想出了一个更好的答案实现。

以下是此解决方案的组成:

  1. SetAttributes必须在基于 BoundedArray 的类的默认构造函数中运行一次
  2. SetAttributes期间,我收集了一个交错的二维数组,其中包含当前BoundedArray子类中的所有索引
  3. 我通过调用Activator.CreateInstance并为每个索引分配一个来创建模板类型的实例

其他需要注意的事项:

  • Set 属性现在采用 int[] s 的可变长度数组,而不是两个 int[] s。 以前,它采用下限和长度,但我意识到只取下限和上限int[],然后使用 LINQ 查询检查是否有任何不是对
  • 的更有意义
  • 我创建了一个名为 IntArray 的静态类,它被SetAttributes测试广泛使用.cs
  • 我试图抛出尽可能多的有用错误,因为我最终可能会大量使用这段代码
  • 我有一种感觉,Combinations(int[][] list1, int[] list2)可能是我的解决方案可以得到最大改进的地方。 我愿意接受有关如何改进所有代码的建议

因此,事不宜迟,我的完整解决方案:

有界数组.cs

using System;
using System.Linq;
using System.Collections.Generic;
namespace test
{
    static class IntArray
    {
        public static int[] FromValues(params int[] values)
        {
            return values;
        }
        public static int[] Sequence(int from, int length)
        {
            if (from < 0 || length < 1)
                throw new ArgumentException();
            return Enumerable.Range(from, length).ToArray();
        }
        public static int[][] Combinations(int[] list1, int[] list2)
        {
            return Combinations(list1.Select(i => new int[] { i }).ToArray(), list2);
        }
        public static int[][] Combinations(int[][] list1, int[] list2)
        {
            List<List<int>> result = new List<List<int>>();
            for (int i = 0; i < list1.Length; i++)
            {
                for (int j = 0; j < list2.Length; j++)
                    result.Add(((int[]) list1.GetValue(i)).Concat(new int[] { list2[j] }).ToList());
            }
            return result.Select(i => i.ToArray()).ToArray();
        }
    }
    abstract class BoundedArray<T>
    {
        public BoundedArray()
        {
            m_data = null;
        }
        public Array Value
        {
            get { return m_data; }
        }
        public T this[params int[] index]
        {
            get
            {
                if (index.Length != m_data.Rank)
                    throw new IndexOutOfRangeException();
                return (T) m_data.GetValue(index);
            }
            set
            {
                if (index.Length != m_data.Rank)
                    throw new IndexOutOfRangeException();
                m_data.SetValue(value, index);
            }
        }
        protected void SetAttributes(params int[][] values)
        {
            // Make sure all of the values are pairs
            if (values.Where(i => i.Length != 2).ToArray().Length > 0)
                throw new ArgumentException("Input arrays must be of length 2.");
            int[] lowerBounds = values.Select(i => i[0]).ToArray();
            int[] lengths = values.Select(i => i[1] - i[0] + 1).ToArray();
            m_data = Array.CreateInstance(typeof(T), lengths, lowerBounds);
            int[][] indices = (lowerBounds.Length != 1) ?
                IntArray.Combinations(IntArray.Sequence(lowerBounds[0], lengths[0]), IntArray.Sequence(lowerBounds[1], lengths[1]))
                : IntArray.Sequence(lowerBounds[0], lengths[0]).Select(i => new int[] { i }).ToArray();
            for (int i = 2; i < lowerBounds.Length; i++)
                indices = IntArray.Combinations(indices, IntArray.Sequence(lowerBounds[i], lengths[i]));
            for (int i = 0; i < indices.Length; i++)
                m_data.SetValue(Activator.CreateInstance(typeof(T)), indices[i]);
        }
        Array m_data;
    }
}

测试.cs

using System;
namespace test
{
    class Program
    {
        // *** Examples of what you can do with BoundedArray ***
        // Multi-dimensional, bounded base array
        class BaseArray : BoundedArray<int>
        {
            public BaseArray()
            {
                SetAttributes(IntArray.FromValues(2, 3), IntArray.FromValues(2, 4));
            }
        }
        // One-dimensional, bounded subclass array
        class SubArray : BoundedArray<BaseArray>
        {
            public SubArray()
            {
                SetAttributes(IntArray.FromValues(4, 6));
            }
        }
        static void Main(string[] args)
        {
            // Initializations used for testing purposes
            BaseArray baseArray = new BaseArray();
            SubArray subArray = new SubArray();
            // Example of assignment
            baseArray[3, 4] = 3;
            subArray[4][2, 3] = 4;
            subArray[4][2] = 3; // Weakness: compiles, but causes IndexOutOfRangeException
            Console.Read();
        }
    }
}

啦?