Стоит ли платить за хранение целых чисел (или любых типов значений) в виде объектов и приведение их обратно к типу int (или типу значений)? - PullRequest
3 голосов
/ 19 июля 2011

В C # стоит ли хранить целые числа (или любые типы значений) в виде объектов и приводить их обратно к типу int (или типу значений)?

В основном мне нужно создать таблицу в памяти.Я могу создать «столбцы», специфичные для каждого возможного типа (так что любой тип примитивного значения, такой как int, double, string и т. Д., А также определяемые пользователем ссылочные типы, которые я хочу сохранить в таблице, такие как Order), или я могу просто хранить ВСЕ как объекти приведите их обратно к правильному типу при доступе к таблице.

Так что мой вопрос в том, какой подход будет работать лучше или оба будут одинаковыми?

Или я должен придерживаться определенных «столбцов»для всех типов значений и сохранить все пользовательские ссылочные типы как объект?

Спасибо - Пример кода ниже - Метод статического теста показывает использование.

public sealed class Columns
{
    public static void Test()
    {
        Columns cols = new Columns(100);
        cols.SetInt(0,Int_Column,12345);
        int value = cols.GetInt(0,Int_Column);

        cols.SetObject(1,Object_Column,12345);
        int value2 = (int)cols.GetObject(1,Object_Column);
    }

    private const int Int_Column = 0;
    private const int String_Column = 1;
    private const int Object_Column = 2;

    private int[] _intCol;
    private string[] _stringCol;
    private object[] _objCol;

    public Columns(int rowCount)
    {
        _intCol = new int[rowCount];
        _stringCol = new string[rowCount];
        _objCol = new object[rowCount];
    }

    public void SetInt(int rowIndex, int colIndex, int value)
    {
        switch(colIndex)
        {
            case Int_Column:
                _intCol[rowIndex] = value;
                break;
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }

    public int GetInt(int rowIndex, int colIndex)
    {
        switch(colIndex)
        {
            case Int_Column:
                return _intCol[rowIndex];
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }

    public void SetString(int rowIndex, int colIndex, string value)
    {
        switch(colIndex)
        {
            case String_Column:
                _stringCol[rowIndex] = value;
                break;
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }

    public string GetString(int rowIndex, int colIndex)
    {
        switch(colIndex)
        {
            case String_Column:
                return _stringCol[rowIndex];
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }

    public void SetObject(int rowIndex, int colIndex, object value)
    {
        switch(colIndex)
        {
            case Object_Column:
                _objCol[rowIndex] = value;
                break;
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }

    public object GetObject(int rowIndex, int colIndex)
    {
        switch(colIndex)
        {
            case Object_Column:
                return _objCol[rowIndex];
            default:
                throw new Exception("Incorrect column index specified.");
        }
    }
}

Ответы [ 3 ]

5 голосов
/ 19 июля 2011

Это называется боксом , и стоимость на самом деле огромна, как в производительности, так и в использовании памяти.Если вы хотите избежать бокса и заставить несколько простых типов, таких как int и double, совместно использовать память, используйте атрибут LayoutKind struct layout , чтобы заставить их делиться памятью, а затем настройте свой список такимТип структуры.Например:

[StructLayout(LayoutKind.Explicit)]
[CLSCompliant(false)]
public struct NumberStackEntry
{
    /// <summary>Type of entry</summary>
    [FieldOffset(0)]
    public EntryTypes entryType;

    /// <summary>Value if double</summary>
    [FieldOffset(4)]
    public double dval;

    /// <summary>Value if ulong</summary>
    [FieldOffset(4)]
    public ulong uval;

    /// <summary>Value if long</summary>
    [FieldOffset(4)]
    public long lval;

    /// <summary>Value if integer</summary>
    [FieldOffset(4)]
    public int ival;
}

Редактировать: Вы можете создать массив из вышеперечисленного, без упаковки, чтобы заполнить членов массива этими значениями.Вы не можете добавить массив в структуру и сделать так, чтобы он разделял память с ссылочными типами не-CLI.

1 голос
/ 19 июля 2011

Поэтому мне очень нравится ответ AresAvatar, за исключением использования LayoutExplicit.

Слово предупреждения, перекрывающиеся поля в структурах предназначены для использования при маршалинге неуправляемых API.Даже там это не работает, но некоторые варианты использования на некоторых платформах повредят среду выполнения CLR.

Взяв его пример, вы можете вместо этого использовать что-то вроде этого:

public struct RecordValue
{
    private object _ref;
    private long _val;

    public string String
    {
        get { return _ref as string; }
        set { _ref = value; }
    }

    public double Double 
    { 
        get { return BitConverter.Int64BitsToDouble(_val); }
        set { _val = BitConverter.DoubleToInt64Bits(value); }
    }

    public long Int64
    {
        get { return _val; }
        set { _val = value; }
    }

    public ulong UInt64
    {
        get { return unchecked((ulong)_val); }
        set { _val = unchecked((long)value); }
    }
    public int Int32
    {
        get { return unchecked((int)_val); }
        set { _val = value; }
    }
}
1 голос
/ 19 июля 2011

Есть стоимость. При хранении int как объекта он должен быть в штучной упаковке . Тип значения хранится непосредственно, а ссылочный тип (которым является объект) хранится в собственном фрагменте памяти, который выделен для него (а затем освобожден сборщиком мусора). При назначении типа значения объекту это в штучной упаковке в объекте, размещенном в управляемой куче. При отбрасывании это распаковано .

В зависимости от ваших потребностей, стоимость бокса может быть актуальной или нет. Если вы не выполняете научные расчеты с огромными объемами данных, играми с большим количеством объектов и высокими требованиями к частоте кадров и т. Д. Я думаю, что стоимость не будет существенной. В этом случае лучше стремиться к читабельному коду, который легко поддерживать и оптимизировать, только если вы заметили проблему с производительностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...