2008-11-22 5 views
3

Я делаю класс Color, а также обеспечить стандартный конструктор какC#, правильное использование статического ключевого слова при разработке основного цвета класса

Color(int red, int green, int blue) 

И тогда я хочу, чтобы обеспечить легкий способ получить наиболее общие цвета, например Color.Blue, Color.Red. Я вижу два возможных варианта:

public static readonly Color Red = new Color(255, 0, 0); 

public static Color Red { get { return new Color(255, 0, 0); } } 

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

Является ли мое рассуждение правильным? Любые советы по лучшим практикам при разработке классов и использованию ключевого слова static были бы замечательными.

ответ

7

Я предполагаю, что вы, вероятно, уже известно, что структура обеспечивает Color-структуру. Я предполагаю, что вы создаете класс Color только для практики.

Вы выразили неуверенность в значении ключевого слова static, хотя вы его правильно использовали.Когда static применяется к члену класса или структуры, это означает, что этот член принадлежит классу в целом и не применяется к отдельным экземплярам. Статические члены данных (поля) создаются только один раз; экземпляры не получают своих собственных копий. Статические функции (методы и свойства) вызывается без ссылки на экземпляр.

Что касается использования памяти, я бы не стал слишком беспокоиться об этом в вашем случае. Ваш класс Color не должен использовать более нескольких байтов на экземпляр (например, структура Color структуры хранит красный, зеленый, синий и альфа в одном 32-битном int.). Если ваш Color действительно является class вместо struct, тогда у вас будет еще несколько байтов в служебных данных (каждый экземпляр будет иметь дополнительный 32-разрядный указатель v-table/typeinfo, а каждая ссылка - дополнительные 32-разрядные), но даже в этом случае вы говорите о 12 байтах или около того на один экземпляр. Если у вас есть предопределенные 100 различных цветов, вы будете использовать < = 1200 байт. На самом деле ничего особенного.

Есть причины для ленивой инстанцирования. Есть классы, в которых do используют много памяти, и те, которые занимают ограниченные системные ресурсы, и те, которые занимают много времени, чтобы построить себя и т. Д. Для этих классов иногда лучше использовать шаблон, например:

class Heavy{ 
    static Heavy first; 
    static Heavy second; 

    public static Heavy First{ 
     get{ 
      if(first == null) 
       first = new Heavy(); 
      return first; 
     } 
    } 
    public static Heavy Second{ 
     get{ 
      if(second == null) 
       second = new Heavy(); 
      return second; 
     } 
    } 
} 

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

Если ваш Color изменен, то единственным правильным способом иметь статический «красный» аксессуар будет ваш второй пример, когда вы создаете новый доступ к каждому доступу. Таким образом, кто-то не может сделать что-то вроде:

Color.Red.G = 255; 

и создать единый общий экземпляр Color.Red, фактически, вместо этого представляет собой желтый цвет.

Но также иметь в виду, что в таком случае, как:

for(int y = 0; y < bmp.Height; y++) 
for(int x = 0; x < bmp.Width; x++) 
    if(bmp.GetPixel(x, y) == Color.Red)) 
     MessageBox.Show("Found a red pixel!"); 

много экземпляров вашего Color класса будет создан. Разумеется, они будут собирать мусор позже, но это все еще аргумент аргумента для вашей первой конструкции выше (или «Тяжелый» пример, который я дал).

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

+0

Отличный ответ! Удаление шахты, ее поддержание. – Shog9

+0

Это был действительно информативный ответ, который помог мне понять идею использования статики намного больше. Благодаря! –

3

Ваши рассуждения и идентификация компромисса кажутся звуковыми. Если вы посмотрите на структуру System.Drawing.Color, вы увидите, что использует второй метод. Накладные расходы на инициализацию новой структуры тривиальны, поэтому это, вероятно, лучше, чем создание большого количества известных цветов.

Я бы ожидал, что Цвет будет непреложной структурой. Но если вы планируете создать класс, вы должны убедиться, что он неизменен, если вы решите использовать первый метод.

+0

Я буду комментировать, а не дублировать сказанное здесь. Если вы не можете использовать System.Drawing или System.Windows.Media, то имитация их проектов, вероятно, лучший путь вперед. Для чего-то простого вы должны использовать структуру. – Nidonocu

1

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

Образец, если вам нужны глобальные данные, по крайней мере, в WPF, должен иметь статическое свойство, которое ссылается на нестатический экземпляр его самого. например Application.Current. Это шаблон, который я дублировал для своих приложений.

0

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

public static readonly Color RED = new Color(255, 0, 0); 

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

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

Если вы действительно хотите пойти на альтернативу геттера, но не заполнить кучу, то, по крайней мере, сделайте создание класса Color статическим. Как это:

private static readonly Color RED = new Color(255, 0, 0); 
    // RED is created once when it is invoked for the first time. 

public static Color Red { 
    get { 
     return RED; 
      // Will return a created RED object or create one 
      // for the first time. 
    } 
} 
+0

Статические инициализаторы запускаются при первом обращении к _class_, а не при первом обращении к _field_. Доступ к Color.Red, если это был первый раз, когда использовался класс Color, инициализировал Color.Green, Color.Yellow и т. Д. Тоже. –