Логика уменьшения порядка битов

У меня есть следующий код, и мне интересно, есть ли более краткий, сокращенный способ написать этот код:

(FontStyle — это .NET Enum с атрибутом Flags)

lblPrompt.Font.Style = FontStyle.Regular;

if (chkBold.Checked)
    lblPrompt.Font.Style |= FontStyle.Bold;
if (chkItalics.Checked)
    lblPrompt.Font.Style |= FontStyle.Italic;
if (chkUnderline.Checked)
    lblPrompt.Font.Style |= FontStyle.Underline;

У меня такое чувство, что ответ заключается в правильном применении оператора and & между CheckBox.Checked и желаемым флагом, подобно следующему:

lblPrompt.Font.Style =
    (chkBold.Checked & FontStyle.Bold)
    | (chkItalics.Checked & FontStyle.Italic)
    | (chkUnderline.Checked & FontStyle.Underline);

Однако это не работает, потому что компилятору явно не нравится мое прямое применение амперсанда с логическим типом и типом Flag/Enum.


person Martin Bliss    schedule 26.07.2012    source источник
comment
Первый фрагмент понятен и прост для понимания. Я бы не изменил его.   -  person Lukasz Madon    schedule 27.07.2012


Ответы (3)


Как насчет чего-то в этом роде:

lblPrompt.Font.Style |=
    (chkBold.Checked ? FontStyle.Bold : 0)
    | (chkItalics.Checked ? FontStyle.Italic : 0)
    | (chkUnderline.Checked ?  FontStyle.Underline : 0);
person Dmytro Shevchenko    schedule 26.07.2012
comment
Это более эффективно, чем предыдущая попытка? Я думаю, что это более лаконично, чего и добивался ОП, но мне интересно, быстрее ли это. Я спрашиваю только потому, что мы имеем дело с побитовыми манипуляциями. - person BlackVegetable; 27.07.2012
comment
Назначение (=) должно быть ИЛИ (|=), чтобы соответствовать исходному поведению. - person HABO; 27.07.2012
comment
@BlackVegetable Я думаю, что ОП заботился только о краткости. Хотя лично я не думаю, что это более читабельно, чем исходный код. - person Dmytro Shevchenko; 27.07.2012
comment
Это решение работает, хотя вы должны предварить его следующим: ( lblPrompt.Font.Style = FontStyle.Regular ), иначе оно просто добавит новые флаги, а не сбросит их в состояние элементов управления пользовательского интерфейса. Я действительно надеялся на решение, которое позволит мне устанавливать флаги без предварительной установки переменной в ноль, для краткости. - person Martin Bliss; 27.07.2012
comment
@MartinBliss хорошо, вы можете назначить FontStyle.Regular = 0 в своем перечислении. Тогда это значение по умолчанию при выполнении битовой логики. - person Dmytro Shevchenko; 27.07.2012
comment
@Shedal Я не понимаю, что ты имеешь в виду. Похоже, вы говорите то же самое, что я только что сказал: вы должны установить для перечисления значение 0 ПЕРЕД кодом в исходном ответе, потому что данный код только добавляет флаги, а не устанавливает их. - person Martin Bliss; 27.07.2012
comment
@Martin Я имел в виду возможность вручную назначать числовые значения для флагов при определении перечисления. Например, Regular=0, Bold=1 и так далее. В этом случае отсутствие флагов уже означает Обычный. Но, возможно, я неправильно понял, чего вам не хватает в решении. - person Dmytro Shevchenko; 27.07.2012
comment
@Shedal Я имею в виду, что, учитывая перечисление, которое я не могу изменить (это не мое перечисление), я должен установить значение переменной перечисления в 0 перед выполнением вашей строки кода, иначе я просто получу предыдущее значение И любые новые установленные флаги. Например: если начальным значением lblprompt.Font.Style является FontStyle.Italic, и у меня отмечены галочки Bold и Underline, результатом (с вашим кодом) будет все три. Если я установлю ноль перед вашим кодом, я получу полужирный и подчеркнутый шрифт, а НЕ курсив... ожидаемое поведение. Я надеялся избежать установки начального флага в соответствии со стилем кода. - person Martin Bliss; 28.07.2012
comment
@MartinBliss просто используйте lblPrompt.Font.Style = вместо lblPrompt.Font.Style |=. - person Dmytro Shevchenko; 28.07.2012
comment
@Shedal Не знаю, почему я об этом не подумал! Я почти уверен, что пробовал это один раз, и это не сработало, но теперь это работает, так что я думаю, что допустил ошибку раньше. Спасибо! - person Martin Bliss; 28.07.2012

Если у вас есть значительно больше вариантов, чем только эти три, возможно, стоит использовать табличное решение:

var table = new [] {
        new { box = chkBold, style = FontStyle.Bold },
        new { box = chkItalics, style = FontStyle.Italic },
        new { box = chkUnderline, style = FontStyle.Underline }
    };

foreach(var combo in table)
{
  if(combo.box.Checked) 
        lblPrompt.Font.Style |= combo.style;        
}

Это не обязательно более кратко, но удерживает вас от повторения.

person Paul Phillips    schedule 26.07.2012
comment
Вы также можете сделать его Dictionary<bool, FontStyle>. - person Dmytro Shevchenko; 27.07.2012
comment
Действительно, все, что может хранить все данные, работает. Мне просто нравятся имена анонимных классов. - person Paul Phillips; 27.07.2012

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

lblPrompt.Font.Style = FontStyle.Regular
             | (chkBold.Checked      ? FontStyle.Bold      : FontStyle.Regular)
             | (chkItalics.Checked   ? FontStyle.Italic    : FontStyle.Regular)
             | (chkUnderline.Checked ? FontStyle.Underline : FontStyle.Regular);

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

person Wug    schedule 26.07.2012
comment
Подобно ответу Шедала, это не гарантирует, что биты FontStyle.Regular, если таковые имеются, установлены, когда все флажки отмечены. Он должен либо использовать |=, либо добавить FontStyle.Regular | . - person HABO; 27.07.2012
comment
Я исправил его, чтобы всегда устанавливать FontStyle.Regular. - person Wug; 27.07.2012