.Net с нижней границей> 0

Несмотря на то, что, возможно, дело в том, что нужно делать, мне нужно создать массив в .Net с нижней границей > 0. Это сначала кажется возможным, используя:

Array.CreateInstance(typeof(Object), new int[] {2}, new int[] {9});

Производит требуемые результаты (массив объектов с нижней границей, установленными в 9). Однако созданный экземпляр массива больше не может передаваться другим методам, ожидающим Object[], давая мне ошибку, говорящую, что:

System.Object[*] нельзя вставить в System.Object[]. Каково это различие в типах массивов и как я могу это преодолеть?

Изменить: test code =

Object x = Array.CreateInstance(typeof(Object), new int[] {2}, new int[] {9});
Object[] y = (Object[])x;

Сбой: "Невозможно передать объект типа" System.Object [*] "для ввода" System.Object [] ".

Я также хотел бы отметить, что этот подход DOES работает при использовании нескольких измерений:

Object x = Array.CreateInstance(typeof(Object), new int[] {2,2}, new int[] {9,9});
Object[,] y = (Object[,])x;

Что отлично работает.

Ответ 2

Причина, по которой вы не можете отбрасывать друг от друга, это то, что это зло.

Предположим, вы создаете массив объекта [5..9] и передаете его функции F в качестве объекта [].

Как функция будет знать, что это 5..9? F ожидает общий массив, но он получает ограниченный. Вы могли бы сказать, что это возможно для него, но это все еще неожиданно, и люди не хотят делать всевозможные пограничные проверки каждый раз, когда хотят использовать простой массив.

Массив является самой простой структурой в программировании, что делает ее слишком сложной, что делает ее непригодной. Вероятно, вам нужна другая структура.

То, что вы делаете, - это класс, который представляет собой ограниченную коллекцию, которая имитирует поведение, которое вы хотите. Таким образом, все пользователи этого класса будут знать, чего ожидать.

class ConstrainedArray<T> : IEnumerable<T> where T : new()
{
    public ConstrainedArray(int min, int max)
    {
        array = new T[max - min];
    }

    public T this [int index]
    {
        get { return array[index - Min]; }
        set { array[index - Min] = value; }
    }

    public int Min {get; private set;}
    public int Max {get; private set;}

    T[] array;

    public IEnumerator<T> GetEnumerator()
    {
        return array.GetEnumarator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return array.GetEnumarator();
    }

}

Ответ 3

Я не уверен, почему это невозможно передать как Object [], но будет непросто, если вы просто создадите настоящий класс, чтобы обернуть массив и обработать свою "странную логику" там?

Вы получили бы преимущества использования реального ссылочного объекта, если бы вы могли добавить "интеллект" в свой класс.

Изменить: Как вы производите свой массив, можете ли вы разместить еще какой-нибудь код? Спасибо.

Ответ 4

Просто сохраните нижнюю границу в целочисленном смещении const и вычтите это значение из того, что ваш источник возвращает как индекс.

Также: это старая функция VB6. Я думаю, что для поддержки этого может быть атрибут.

Ответ 5

Знай это старый вопрос, но чтобы полностью его объяснить.

Если тип (в данном случае одномерный массив с нижней границей> 0) не может быть создан типизированным кодом, тогда просто отраженный экземпляр типа не может быть использован типизированным кодом.

То, что вы заметили, уже есть в документации:

https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names

Обратите внимание, что с точки зрения времени выполнения, MyArray []! = MyArray [*], но для многомерных массивов эти два обозначения эквивалентны. Это is, Type.GetType("MyArray [,]") == Type.GetType("MyArray [*, *]") оценивается как истина.

В c #/vb/... вы можете сохранить этот отраженный массив в объекте, передать его как объект и использовать только отражение для доступа к его элементам.

-

Теперь вы спрашиваете "почему вообще существует LowerBound?", Ну, COM-объект - это не .NET, его можно было бы написать в старом VB6, у которого фактически был объект массива, для которого LowerBound был установлен в 1 (или что-нибудь в VB6 имело такую свободу или проклятие, зависит от кого ты спрашиваешь). Чтобы получить доступ к первому элементу такого объекта, вам на самом деле нужно использовать 'comObject (1)' вместо 'comObject (0)'. Поэтому причина для проверки нижней границы заключается в том, что когда вы выполняете перечисление такого объекта, чтобы знать, где начать перечисление, так как функции элемента в COM-объекте ожидают, что первый элемент будет иметь значение LowerBound, а не Zero (0), разумно было поддерживать та же логика в таких случаях. Представьте, что ваше значение элемента get для первого элемента равно 0, и используйте некоторый объект Com для передачи такого экземпляра элемента со значением индекса 1 или даже со значением индекса 2001 в метод, код будет очень запутанным.

Проще говоря: это в основном только для устаревшей поддержки!