簡體   English   中英

C#-可嵌套的有界數組

[英]C# - Nestable, bounded arrays

我正在將用Pascal(16位編譯)編寫的游戲移植到C#(因此它將在XP以后的計算機上運行)。 根據我收集的內容,在Pascal中,可以通過以下語法在單元/程序的type部分中鍵入define:

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

    SubArray = array [0 .. 3] of BaseArray;

不幸的是,我還收集到了在C#中無法鍵入define的信息。 但是,我正在嘗試一種解決方法。 到目前為止,這就是我所擁有的:

BoundedArray.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;
    }
}

test.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();
        }
    }
}

我檢查baseArray ,和默認值m_data是零,因為它們是int秒。 但是,在subArraysubArray的默認值為m_data由於某種原因, subArray的數組內部的BaseArray實例尚未初始化。 如何使默認構造函數運行?

編輯:目前真正的問題是為什么不m_data.Initialize(); SetAttributes方法中初始化m_data所有元素? MSDN上的文檔似乎表明它應該...

編輯:所以我認為問題在於System.Array.Initialize僅適用於值類型。 由於類是C#中的引用類型,因此System.Array.Initialize不執行任何操作。 因此,我必須找到一種方法來初始化具有可變尺寸,長度和下限的引用類型的數組。

您有一個單維數組SubArray ,其中包含BaseArray對象,這些對象是整數的二維數組。 代替Pascal type ,您可以定義一個自定義C#類,該類將覆蓋indexer運算符以提供完全相同的行為。

編輯所以,在帕斯卡你有這個:

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; }
    }
}

嗯,我已經做了一些改變,當你想創建一個實例SubArray ,你應該通過BaseArray數據進行初始化的來源。

據我了解,您想將值從BaseArray設置為SubArray

這是我的工作:

BoundedArray.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;
}

Test.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();
    }
}

我已經回答了我的問題一次,但我想出了一個更好的實現我的回答。

以下是此解決方案的組成:

  1. SetAttributes必須在基於BoundedArray的類的默認構造函數中運行一次
  2. SetAttributes期間,我收集了當前BoundedArray子類中所有索引的鋸齒狀二維數組
  3. 我通過調用Activator.CreateInstance並為每個索引分配一個實例來創建模板類型的實例

其他注意事項:

  • Set屬性現在采用int[]的可變長度數組,而不是兩個int[] 以前,它采用下限和長度,但是我意識到只接受下限和上限的int[]才有意義,然后使用LINQ查詢來檢查是否存在不存在的內容。對
  • 我創建了一個名為IntArray的靜態類,該類由SetAttributestest.cs廣泛使用。
  • 我試圖拋出盡可能多的有用錯誤,因為我可能最終會大量使用此代碼
  • 我覺得Combinations(int[][] list1, int[] list2)可能是我的解決方案中可以找到最大改進的地方。 我願意就如何改進我的所有代碼提出建議

因此,事不宜遲,我的完整解決方案是:

BoundedArray.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;
    }
}

test.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();
        }
    }
}

hou?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM