Как вы передаете несколько значений перечисления в C#?
Иногда при чтении кода C# других пользователей я вижу метод, который принимает несколько значений перечисления в одном параметре. Я всегда думал, что это было здорово, но никогда не смотрел на это.
Ну, теперь я думаю, что мне это может понадобиться, но я не знаю, как
- установить подпись метода, чтобы принять это
- работать со значениями в методе
- определить перечисление
чтобы достичь такого рода вещи.
В моей конкретной ситуации я хотел бы использовать System.DayOfWeek, который определяется как:
[Serializable]
[ComVisible(true)]
public enum DayOfWeek
{
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6
}
Я хочу иметь возможность передать одно или несколько значений DayOfWeek моему методу. Смогу ли я использовать этот конкретный enum как есть? Как мне сделать 3 вещи, перечисленные выше?
10 ответов
Когда вы определяете перечисление, просто приписывайте его с помощью [Flags], устанавливайте значения в степени двух, и это будет работать таким образом.
Ничто иное не изменится, кроме передачи нескольких значений в функцию.
Например:
[Flags]
enum DaysOfWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64
}
public void RunOnDays(DaysOfWeek days)
{
bool isTuesdaySet = (days & DaysOfWeek.Tuesday) == DaysOfWeek.Tuesday;
if (isTuesdaySet)
//...
// Do your work here..
}
public void CallMethodWithTuesdayAndThursday()
{
this.RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}
Дополнительные сведения см. В документации MSDN "Типы перечисления".
Редактировать в ответ на дополнения к вопросу.
Вы не сможете использовать это перечисление как есть, если только вы не захотите сделать что-то вроде передачи его как массива array/collection/params. Это позволит вам передать несколько значений. Синтаксис флагов требует, чтобы Enum был указан в качестве флагов (или чтобы убить язык таким образом, чтобы он не был разработан).
Я думаю, что более элегантным решением является использование HasFlag():
[Flags]
public enum DaysOfWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64
}
public void RunOnDays(DaysOfWeek days)
{
bool isTuesdaySet = days.HasFlag(DaysOfWeek.Tuesday);
if (isTuesdaySet)
{
//...
}
}
public void CallMethodWithTuesdayAndThursday()
{
RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}
Я второй ответ Рида. Однако при создании перечисления вы должны указать значения для каждого члена перечисления, чтобы он представлял собой своего рода битовое поле. Например:
[Flags]
public enum DaysOfWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
None = 0,
All = Weekdays | Weekend,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
Weekend = Sunday | Saturday,
// etc.
}
В моей конкретной ситуации я хотел бы использовать System.DayOfWeek
Вы не можете использовать System.DayOfWeek как [Flags]
Перечисление, потому что вы не можете его контролировать. Если вы хотите иметь метод, который принимает несколько DayOfWeek
тогда вам придется использовать params
ключевое слово
void SetDays(params DayOfWeek[] daysToSet)
{
if (daysToSet == null || !daysToSet.Any())
throw new ArgumentNullException("daysToSet");
foreach (DayOfWeek day in daysToSet)
{
// if( day == DayOfWeek.Monday ) etc ....
}
}
SetDays( DayOfWeek.Monday, DayOfWeek.Sunday );
В противном случае вы можете создать свой собственный [Flags]
перечисление, как указано многими другими респондентами, и использовать побитовые сравнения.
[Flags]
public enum DaysOfWeek
{
Mon = 1,
Tue = 2,
Wed = 4,
Thur = 8,
Fri = 16,
Sat = 32,
Sun = 64
}
Вы должны указать числа и увеличивать их следующим образом, потому что они хранят значения побитовым образом.
Затем просто определите свой метод, чтобы взять это перечисление
public void DoSomething(DaysOfWeek day)
{
...
}
и назвать это сделать что-то вроде
DoSomething(DaysOfWeek.Mon | DaysOfWeek.Tue) // Both Monday and Tuesday
Чтобы проверить, было ли включено одно из значений перечисления, проверьте их, используя побитовые операции, такие как
public void DoSomething(DaysOfWeek day)
{
if ((day & DaysOfWeek.Mon) == DaysOfWeek.Mon) // Does a bitwise and then compares it to Mondays enum value
{
// Monday was passed in
}
}
[Flags]
public enum DaysOfWeek{
Sunday = 1 << 0,
Monday = 1 << 1,
Tuesday = 1 << 2,
Wednesday = 1 << 3,
Thursday = 1 << 4,
Friday = 1 << 5,
Saturday = 1 << 6
}
вызвать метод в этом формате
MethodName(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
Реализуйте метод EnumToArray, чтобы получить переданные параметры
private static void AddEntryToList(DaysOfWeek days, DaysOfWeek match, List<string> dayList, string entryText) {
if ((days& match) != 0) {
dayList.Add(entryText);
}
}
internal static string[] EnumToArray(DaysOfWeek days) {
List<string> verbList = new List<string>();
AddEntryToList(days, HttpVerbs.Sunday, dayList, "Sunday");
AddEntryToList(days, HttpVerbs.Monday , dayList, "Monday ");
...
return dayList.ToArray();
}
Пометьте свое перечисление атрибутом [Flags]. Также убедитесь, что все ваши значения являются взаимоисключающими (два значения не могут сложиться, чтобы равняться другому), как 1,2,4,8,16,32,64 в вашем случае
[Flags]
public enum DayOfWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64
}
Если у вас есть метод, который принимает перечисление DayOfWeek, используйте побитовое или оператор (|), чтобы использовать несколько членов вместе. Например:
MyMethod(DayOfWeek.Sunday|DayOfWeek.Tuesday|DayOfWeek.Friday)
Чтобы проверить, содержит ли параметр конкретный элемент, используйте побитовое и оператор (&) с элементом, для которого вы проверяете.
if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");
Рид Копси прав, и я хотел бы добавить к исходному сообщению, если смогу, но я не могу, поэтому мне придется ответить вместо этого.
Опасно просто использовать [Flags] для любого старого перечисления. Я полагаю, что вы должны явно изменить значения перечисления на степени двух при использовании флагов, чтобы избежать конфликтов в значениях. Смотрите рекомендации для FlagsAttribute и Enum.
С помощью опубликованных ответов и этих:
- Класс FlagsAttribute (посмотрите на сравнение использования и не использования атрибута [Flags])
- Атрибут Enum Flags
Я чувствую, что понимаю это довольно хорошо.
Благодарю.
Нечто подобное должно показать то, что вы ищете:
[Flags]
public enum SomeName
{
Name1,
Name2
}
public class SomeClass()
{
public void SomeMethod(SomeName enumInput)
{
...
}
}