Различают несколько типов, которые по сути являются Int32 - PullRequest
1 голос
/ 12 ноября 2011

У меня есть приложение, которое связывается с базой данных. Каждая таблица имеет уникальный идентификатор.

Когда я извлекаю строку из базы данных, я заполняю класс всеми полями (это весь сгенерированный код).

Первоначально я просто использовал Int32 в качестве типа идентификатора, но продолжал обнаруживать, что неподходящие типы передаются в методы и т. Д.

Мое решение для этого было создать определенный тип, который я называю idUser (где User - фактическое имя таблицы). Причина этого в том, что если я пытаюсь передать idSalesMan в метод, который ожидает idUser, он генерирует ошибку времени компиляции, которая действительно полезна и мешает мне делать ошибки школьника.

Код idUser выглядит следующим образом ..

[Serializable]
public struct idUser : IComparable
{
    public idUser(int InitVal) { this.m_Main=InitVal; }
    private int m_Main;
    public int Main { get { return m_Main; } set { m_Main = value; }}
    public static implicit operator int(idUser Main) { return Main.m_Main; }
    public static implicit operator idUser(int Main) { return new idUser(Main); }
    public static bool operator ==(idUser one, idUser two) { return one.m_Main == two.m_Main; }
    public static bool operator !=(idUser one, idUser two) { return one.m_Main != two.m_Main; }
    public static bool operator <(idUser one, idUser two) { return one.m_Main < two.m_Main; }
    public static bool operator >(idUser one, idUser two) { return one.m_Main > two.m_Main; }
    public override string ToString() {{ return this.m_Main.ToString(CultureInfo.InvariantCulture); }}
    public override bool Equals(object obj) { return this.m_Main == ((idUser)obj).m_Main; }
    public override int GetHashCode() { return this.m_Main.GetHashCode(); }
    public int CompareTo(object obj) { return this.m_Main.CompareTo(((idUser)obj).m_Main); }
}

Это прекрасно работает, легко (так как генерируется с помощью написанного мною инструмента) и предотвращает проблемы, о которых я говорил выше.

Однако, поскольку моя база данных содержит около 100 таблиц, она генерирует много кода и довольно большой исполняемый файл. (это не главная проблема).

Мне было любопытно, что влияет на производительность использование вышеупомянутой структуры, а не просто стандартного Int32, и я был довольно шокирован.

Создаем List<>, заполняя его, затем проверяя наличие некоторых ключей.

При использовании List<idUser> для его заполнения требуется в 3 раза больше времени, а для проверки некоторых добавленных элементов - в 5 раз больше.

Это довольно серьезный хит, поэтому я искал альтернативные способы сделать это.

В идеале я бы хотел сказать ...

public struct idUser : Int32 { }
public struct idCustomer : Int32 { }

Но это, очевидно, не работает.

Как я уже говорил выше, он отлично работает, как есть, но просто имеет снижение производительности. У кого-нибудь есть идеи о том, как включить строгую проверку типов, сохранив при этом производительность Int32?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 12 ноября 2011

Я подозреваю, что могу объяснить проблему производительности с поиском значений в List<T> - вы не реализуете IEquatable<T>, поэтому любой вызов Equals должен содержать значение, с которым он сравнивается. Вы также должны реализовать IComparable<T> для сравнения.

// Please don't use camelCased type names...
// I'd probably use UserId, CustomerId etc, partly to avoid non-interfaces
// starting with I.
public struct IdUser : IComparable, IComparable<IdUser>, IEquatable<IdUser>
{
   ...
   public bool Equals(IdUser other) { return m_Main == other.m_Main; }
   public int CompareTo(IdUser other) { return m_Main.CompareTo(other.mMain); }
}

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

Обратите внимание, что в большинстве случаев я ожидаю, что основная часть снижения производительности будет начинаться с передачи данных из базы данных; Сравнение производительности заполнения списка только данными в памяти не является реалистичным тестом влияния производительности на ваше реальное приложение.

1 голос
/ 12 ноября 2011

Различают несколько типов, которые по сути являются Int32

Как насчет использования перечислений?

1 голос
/ 12 ноября 2011

Кажется, что проблема с производительностью заключается в следующем:

Создание списка <>, заполнение его, затем проверка на наличие некоторые ключи ..

Это почти наверняка связано с тем, что ваш тип не реализует IEquatable<T>, что приводит к появлению бокса при сравнении на равенство. Реализуйте этот интерфейс и проверьте, улучшается ли это.

List<T> использует EqualityComparer<T>.Default для сравнения на равенство (скажем, когда вы звоните Contains). Теперь этот компаратор пытается использовать метод Equals(T other) из IEquatable<T>, если это возможно, что позволяет избегать типов значений бокса. Если тип не реализует интерфейс, он возвращается к object.Equals(object obj), что требует упаковки типов значений.

Конечно, единственный способ решить все проблемы с производительностью - это тестирование и профилирование.

С другой стороны, вы уверены, что не хотите использовать набор, такой как HashSet<T>, а не список? Вызов List<T>.Contains в цикле настоятельно рекомендует вам требовать семантики набора, а не семантики списка.

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