Можно ли указать параметр цвета по умолчанию в C# 4.0?

Вот пример функции:

public void DrawSquare(int x, int y, Color boxColor = Color.Black)
{
    //Code to draw the square goes here 
}

Компилятор продолжает выдавать мне ошибку: Default parameter value for 'boxColor'must be a compile-time constant

я пытался

Color.Black, 
Color.FromKnownColor(KnownColor.Black), and 
Color.FromArgb(0, 0, 0)

Как сделать Color.Black цветом по умолчанию? Кроме того, я не хочу использовать строку Black для ее указания (я знаю, что это сработает). Мне нужно значение Color.Black.


person Mike Webb    schedule 15.12.2010    source источник


Ответы (3)


Color.Black является статическим, а не константным, поэтому нет, вы не можете этого сделать.

Чтобы использовать значение по умолчанию, вы можете сделать параметр обнуляемым (Color?), а если он нулевой, то установить для него значение Black.

person Brian Ball    schedule 15.12.2010
comment
У меня было это в моем ответе, но если вы собираетесь указать нулевой аргумент, почему бы просто не указать Color.Black? :) - person George Johnston; 15.12.2010
comment
@George: Color.Black - это статика, а не константа. - person Vlad; 15.12.2010
comment
Color — это структура, поэтому, если вы используете Nullable‹Color› в качестве типа (или в C# Color? для краткости), то он может быть нулевым. - person Brian Ball; 15.12.2010
comment
Действительно, вы явно ссылаетесь на Color?, забирая мой комментарий. - person Vlad; 15.12.2010

Сделай это:

void foo(... Color boxColor = default(Color))
{
   if(object.Equals(boxColor, default(Color))) boxColor = Color.Black;

  // ...
}

Небольшое отступление: мне нравится использовать статический метод object.Equals, потому что это последовательный способ записи сравнения на равенство. С такими ссылочными типами, как string, str.Equals("abc") может вызывать NRE, а string.Equals(str, "abc"[,StringComparison.___]) — нет. Color является типом значения и, следовательно, никогда не будет нулевым, но лучше быть последовательным в стиле кода, особенно при нулевых дополнительных затратах. Очевидно, это не относится к примитивам, таким как int и даже DateTime, где == четко указывает/сообщает о математическом сравнении на равенство.

Или с нулевыми значениями (ответ Брайана Болла):

void foo(... Color? boxColor = null)
{
   if(boxColor == null) boxColor = Color.Black;

  // ...
}
person Mr. TA    schedule 15.12.2010
comment
почему бы не просто if (boxColor == default(Color))? - person Vlad; 15.12.2010
comment
Это не имеет значения. Я предпочитаю нотацию Equals, но с типами значений '==' идентичен. - person Mr. TA; 15.12.2010
comment
@Мистер. TA: ну, в этом случае лучше было бы использовать Color.Equals вместо object.Equals. Или лучше default(Color).Equals(boxColor) чтобы вы использовали виртуальную функцию. На мой взгляд, == более читабелен, но это вопрос личного вкуса. - person Vlad; 15.12.2010
comment
Возможно, это производительность и то, как алгоритм проверяет равенство. Если я не ошибаюсь, я заметил, что someString == abc не совпадает с производительностью someString.Equal(abc), лучше всего использовать Equal(). Цвет - это тип значения, который в основном == и Equal() производят одно и то же, но для ссылочного типа (кроме строки) == и Equal() дают совершенно другое значение, == для проверки ссылки равно, в то время как Equal() зависит на типе, если метод Equal() переопределен. - person CallMeLaNN; 21.01.2011
comment
@Vlad: в типах значений нет виртуальных функций, а Color.Equals — это то же самое, что и object.Equals, то же самое, что и default(Color).Equals(boxColor). Единственное преимущество, IMO, использования object.Equals или Color.Equals вместо default(Color).Equals(boxColor) заключается в том, что вы подчеркиваете тот факт, что вы сравниваете два значения, почти так же, как написано == - это проблема читабельности. Кроме того, для согласованности object.Equals(x,y) лучше, чем x.Equals(y), потому что со ссылочными типами x.Equals(y) может вызывать NRE, тогда как с object.Equals(x,y) вы в безопасности. - person Mr. TA; 31.01.2011
comment
@Мистер. TA: (1) Color.Equals является виртуальным, см. msdn.microsoft.com/ en-us/library/e03x8ct2.aspx. (2) default(Color) никогда не бывает null. (3) Color.Equals лучше, чем object.Equals, потому что последний может сравнивать только ссылки (однако он может делать правильные вещи для типов значений). Дополнительные сведения по теме: blogs.msdn.com/b/ericlippert/archive/2009/04/09/ - person Vlad; 31.01.2011
comment
@Vlad: (1) Это не совсем виртуально, потому что для типа значения нет v-таблицы. Во-вторых, нет никакой пользы от использования object.Equals(x,y) вместо x.Equals(y) в отношении того, является ли Equals виртуальным или нет. (2) я имел в виду удобочитаемость и согласованность кода; Я сказал, что для ссылочных типов это может быть проблемой, и поэтому проще придерживаться правила всегда использовать object.Equals(x,y). (3) Нет абсолютно никакой разницы между object.Equals(x,y) и Color.Equals(x,y), это одно и то же. Ссылки на самом деле не имеют отношения к нашему обсуждению, но все равно спасибо. - person Mr. TA; 01.02.2011
comment
@Мистер. TA: (1) в каком смысле не совсем виртуальный? Наблюдаемое поведение заключается в том, что вместо Object.Equals вызывается конкретный Color.Equals. Есть ли vtable или нет, это деталь реализации. Поведение такое же, как у виртуальной функции, объявление такое же, как и у виртуальной функции, поэтому функция является виртуальной. Вы можете найти функцию Color.Equals в Reflector, чтобы убедиться, что это не совсем то же самое, что и object.Equals. - person Vlad; 01.02.2011
comment
@Мистер. Т.А.: (3) Разница есть, можете сами проверить. Код в Color.Equals выглядит так: public override bool Equals(object obj) { if (obj is Color) { Color color = (Color) obj; if (((this.value == color.value) && (this.state == color.state)) && (this.knownColor == color.knownColor)) { return ((this.name == color.name) || (((this.name != null) && (color.name != null)) && this.name.Equals(this.name))); } } return false; } - person Vlad; 01.02.2011
comment
@Влад: (1) Верно. Но это не меняет того факта, что правильный метод вызывается независимо от вызова object.Equals(color1, color2) или color1.Equals(color2). (3) Я имел в виду статические методы object.Equals(x,y) и Color.Equals(x,y), а вы описываете методы экземпляра object.Equals(y) и Color.Equals(y). Моя первоначальная точка зрения заключалась в том, что использование статического метода object.Equals(x,y) является лучшим подходом по всем направлениям, как для типов значений, так и для ссылочных типов. - person Mr. TA; 01.02.2011
comment
Я думаю, что @Vlad выглядит более читаемым, поэтому +1, поскольку кто-то другой поймет это быстрее, и хотя обсуждение виртуальных функций все еще проходит через мою голову, поскольку я все еще относительно новичок, я предполагаю, что любая экономия производительности не будет такой большой вещью... - person Will Croxford; 12.05.2018

Что плохого в простоте?

public void DrawSquare(int x, int y)
{
    DrawSquare(x,y,Color.Black);
}

public void DrawSquare(int x, int y, Color color)
{
   // Do your thing.
}
person George Johnston    schedule 15.12.2010
comment
Реальная функция не так проста. Он имеет около 10 параметров (большинство из которых являются необязательными и могут быть указаны как необязательные). Плюс есть 5 или 6 разных функций с этими параметрами и по две вариации каждой функции. Чтобы сделать вышеперечисленное, нужно добавить слишком много функций. Но спасибо за предложение. - person Mike Webb; 15.12.2010