0

Pascal (16 ビットでコンパイル) で記述されたゲームを C# に移植しています (したがって、XP より新しいマシンで実行されます)。私が収集したものから、Pascal では、次のような構文を使用して、ユニット/プログラムの型セクションで型定義を行うことができます。

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

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

残念ながら、C# で型定義を行うことは不可能であることもわかりました。ただし、回避策を試しています。これまでのところ、これは私が持っているものです:

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は s であるためゼロintです。ただし、 ではsubArray、 のデフォルト値m_dataは nullです。BaseArrayの配列内のインスタンスはsubArray、何らかの理由で初期化されていません。デフォルトのコンストラクターを実行するにはどうすればよいですか?

m_data.Initialize();編集:現時点での本当の問題は、SetAttributesメソッドですべての要素を初期化しないのはなぜm_dataですか? MSDNのドキュメントは、それがすべきことを示しているようです...

編集:だから、問題はSystem.Array.Initialize値型でのみ機能すると思います。クラスは C# の参照型であるため、System.Array.Initialize何もしません。したがって、可変次元、長さ、および下限の参照型配列を初期化する方法を見つける必要があります。

4

3 に答える 3

0

私はすでに自分の質問に一度答えましたが、答えのより良い実装を思いつきました。

このソリューションの構成は次のとおりです。

  1. SetAttributesに基づくクラスのデフォルトのコンストラクターで、一度実行する必要がありますBoundedArray
  2. の間に、現在のサブクラスSetAttributesのすべてのインデックスのギザギザの 2 次元配列を収集しますBoundedArray
  3. Activator.CreateInstanceインデックスごとに 1 つを呼び出して割り当てることにより、テンプレート タイプのインスタンスを作成します。

その他の注意事項:

  • int[]セット属性は、2 つの の代わりに の可変長配列を取るようになりましたint[]int[]以前は、下限と長さを取得していましたが、下限と上限である s を取得し、LINQ クエリを使用してペアではないものがないことを確認する方が理にかなっていることに気付きました
  • という静的クラスを作成しました。これは、test.csIntArrayで広く使用されています。SetAttributes
  • おそらくこのコードを頻繁に使用することになるので、できるだけ多くの有用なエラーをスローしようとしました
  • 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();
        }
    }
}

考え?

于 2013-10-28T01:58:16.303 に答える
0

のインスタンスを作成する場合は、初期化するデータのソースとして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();
    }
}
于 2013-10-27T06:20:27.107 に答える