Подтвердить что ты не робот

В С# - значения в списке <struct> в штучной упаковке?

Предположим, что я объявляю общий список, содержащий значения типа struct:

struct MyStruct {
    public MyStruct(int val1, decimal val2) : this() {
        Val1 = val1;
        Val2 = val2;
    }
    public int Val1 {get; private set;}
    public decimal Val2 {get; private set;}
}

List<MyStruct> list;

Сохраняет ли List < > каждое отдельное значение в виде вложенной структуры, выделенной отдельно в куче? Или это умнее, чем это?

4b9b3361

Ответ 1

Нет бокса.

"Нет, бокса не будет. Это была одна из главных целей разработки Generics".

http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/359cf58a-f53d-478e-bc31-1507e77c9454/

"Если тип типа используется для типа T, то компилятор генерирует реализацию класса List<T> специально для этого типа значений. Это означает, что элемент списка объекта List<T> не должен быть помещен в бокс перед элемент, и после создания около 500 элементов списка сохраненная память не содержит элементы списка бокса больше, чем память, используемая для генерации реализации класса."

http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

Ответ 2

Он не помещается в бокс, но данные будут копировать оригинала, и каждый раз, когда вы извлекаете данные, он будет копировать снова. Это, как правило, позволяет легко потерять изменения. Таким образом, вы должны стремиться не писать изменяемые структуры. Если MyStruct фактически представляет собой единицу измерения (или аналогичную), сделайте ее классом. И если это мера, сделайте ее неизменной (нет общедоступных настраиваемых членов).

И в любом случае, не открывайте поля! Использовать свойства; -p

Например:

struct MyStruct {
    public MyStruct(int val1, decimal val2) {
        this.val1 = val1;
        this.val2 = val2;
    }
    private readonly int val1;
    private readonly decimal val2;
    public int Val1 {get {return val1;}}
    public decimal Val2 {get {return val2;}}
}

Или, альтернативно (С# 3.0):

struct MyStruct {
    public MyStruct(int val1, decimal val2) : this() {
        Val1 = val1;
        Val2 = val2;
    }
    public int Val1 {get; private set;}
    public decimal Val2 {get; private set;}
}

Ответ 3

Нет, List<T> ничего не помещает. Внутренне он сохраняет свои значения в простом массиве:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection,    IEnumerable
{
    // Fields
    private const int _defaultCapacity = 4;
    private static T[] _emptyArray;
    private T[] _items;
    private int _size;

Ответ 4

typeof(List<>) // or informally List`1

... является общим типом. Типичные типы или параметризованные типы отличаются тем, что они скомпилированы обычным способом, но во время выполнения они снова скомпилированы в зависимости от их использования.

Если вы поместите ValueType в общий список, например. List <int> поведение во время выполнения представляет собой угрозу, которая, как если бы она хранила тип int (который является копией по значению). Бокс не должен проходить, потому что вам не нужно лечить, как будто тип этого List`1 - это нечто иное, чем int.

До .NET 2.0 это не удалось сделать, поэтому позорный класс ArrayList поддерживал массив объектов, который означал, что ValueType (ints или structs) должен быть помещен в коробку для размещения в этом контейнере.

Это не следует путать с дженериками Java, что совсем другое. Java generics был реализован с типом стирания, который не дает вам такого же повышения производительности. Что делает Java, так это то, что как только компилятор завершит проверку типов, он будет передавать все объекту. Вот почему вы не можете отразиться на дженериках Java, когда можете использовать систему типа generic типа .NET.

Ответ 5

Список хранит все в массивах типа Т. Нет бокса, но массив выделяется в куче.

Ответ 6

Нет бокса, поэтому он немного быстрее, чем не общий.

Ответ 7

Нет бокса, что один из Преимущества дженериков:

List<int> list1 = new List<int>();    
// No boxing, no casting:
list1.Add(3);

// Compile-time error:
// list1.Add("It is raining in Redmond.");